added others frameworks
This commit is contained in:
parent
7b8444bce0
commit
720f343d72
367 changed files with 42826 additions and 7420 deletions
17
Podfile
17
Podfile
|
@ -1,17 +1,16 @@
|
|||
platform :ios, '7.0'
|
||||
|
||||
#GPUImage
|
||||
#DLCImagePickerController
|
||||
#TMQuiltView
|
||||
#ShareKit
|
||||
#TSAlertView
|
||||
#ASIHTTPRequest
|
||||
#iRate
|
||||
#ViewDeck
|
||||
#InAppSettingsKit
|
||||
|
||||
#pod 'DLCImagePickerController', '~> 0.0.1'
|
||||
pod 'SBJson', '~> 3.2'
|
||||
pod 'GoogleAnalytics-iOS-SDK', '~> 3.0.3'
|
||||
pod 'SDWebImage','~> 3.5.2'
|
||||
pod 'Reachability','~> 3.1.1'
|
||||
pod "MBProgressHUD", "0.8"
|
||||
pod "MBProgressHUD", "~> 0.8"
|
||||
pod 'InAppSettingsKit', '~> 2.0'
|
||||
pod 'ASIHTTPRequest', '~> 1.8.1'
|
||||
pod 'iRate', '~> 1.9.2'
|
||||
pod 'ViewDeck', '~> 2.3.1'
|
||||
pod 'TMQuiltView', '~> 0.0.1'
|
||||
#pod 'ShareKit', '~> 2.5.3'
|
27
Podfile.lock
27
Podfile.lock
|
@ -1,24 +1,49 @@
|
|||
PODS:
|
||||
- ASIHTTPRequest (1.8.1):
|
||||
- ASIHTTPRequest/ASIWebPageRequest
|
||||
- ASIHTTPRequest/CloudFiles
|
||||
- ASIHTTPRequest/S3
|
||||
- Reachability
|
||||
- ASIHTTPRequest/ASIWebPageRequest (1.8.1):
|
||||
- Reachability
|
||||
- ASIHTTPRequest/CloudFiles (1.8.1):
|
||||
- Reachability
|
||||
- ASIHTTPRequest/S3 (1.8.1):
|
||||
- Reachability
|
||||
- GoogleAnalytics-iOS-SDK (3.0.3)
|
||||
- InAppSettingsKit (2.0)
|
||||
- iRate (1.9.2)
|
||||
- MBProgressHUD (0.8)
|
||||
- Reachability (3.1.1)
|
||||
- SBJson (3.2)
|
||||
- SDWebImage (3.5.2):
|
||||
- SDWebImage/Core
|
||||
- SDWebImage/Core (3.5.2)
|
||||
- TMQuiltView (0.0.1)
|
||||
- ViewDeck (2.3.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- ASIHTTPRequest (~> 1.8.1)
|
||||
- GoogleAnalytics-iOS-SDK (~> 3.0.3)
|
||||
- MBProgressHUD (= 0.8)
|
||||
- InAppSettingsKit (~> 2.0)
|
||||
- iRate (~> 1.9.2)
|
||||
- MBProgressHUD (~> 0.8)
|
||||
- Reachability (~> 3.1.1)
|
||||
- SBJson (~> 3.2)
|
||||
- SDWebImage (~> 3.5.2)
|
||||
- TMQuiltView (~> 0.0.1)
|
||||
- ViewDeck (~> 2.3.1)
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
ASIHTTPRequest: 162783e0cd71bdd3ff1ceed0cd5fa9505e0116a8
|
||||
GoogleAnalytics-iOS-SDK: 7b0e55cfe5e70d60478a7b105f15ac71e8bc373e
|
||||
InAppSettingsKit: 2b85ba925a81634860461c21274f54b130c84614
|
||||
iRate: 7c4bc22ab4a8752185d84bed7a98dc111c8212a5
|
||||
MBProgressHUD: 2bbc6f470111daf7f3eaa4eb12b8cbf01c4c0622
|
||||
Reachability: be4883bb93f31e38266ae3365e5600a317aae735
|
||||
SBJson: abc2bf2baef456d5dae213f9826fe2b6fdf19861
|
||||
SDWebImage: fe7ce01ae4e0a884d168f59c9dd82d35baf8429e
|
||||
TMQuiltView: 520d09d6a98f1a6aa75ed92a91123ecc79bab62c
|
||||
ViewDeck: 2cdc67c4b41a10cafc7556b982f028409e33604d
|
||||
|
||||
COCOAPODS: 0.29.0
|
||||
|
|
35
Pods/ASIHTTPRequest/Classes/ASIAuthenticationDialog.h
generated
Normal file
35
Pods/ASIHTTPRequest/Classes/ASIAuthenticationDialog.h
generated
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// 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 (retain) ASIHTTPRequest *request;
|
||||
@property (assign) ASIAuthenticationType type;
|
||||
@property (assign) BOOL didEnableRotationNotifications;
|
||||
@property (retain, nonatomic) UIViewController *presentingController;
|
||||
@end
|
487
Pods/ASIHTTPRequest/Classes/ASIAuthenticationDialog.m
generated
Normal file
487
Pods/ASIHTTPRequest/Classes/ASIAuthenticationDialog.m
generated
Normal file
|
@ -0,0 +1,487 @@
|
|||
//
|
||||
// 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 (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 = [[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] applicationFrame];
|
||||
|
||||
// Swap the frame height and width if necessary
|
||||
if (UIDeviceOrientationIsLandscape(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:row inSection: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
|
||||
{
|
||||
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)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 {
|
||||
[[self parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTitle
|
||||
{
|
||||
UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
|
||||
UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
|
||||
if (UIInterfaceOrientationIsPortrait([[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
|
||||
|
||||
[[self presentingController] presentModalViewController:self animated:YES];
|
||||
}
|
||||
|
||||
#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];
|
||||
|
||||
NSUInteger s = [indexPath section];
|
||||
NSUInteger 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
|
103
Pods/ASIHTTPRequest/Classes/ASICacheDelegate.h
generated
Normal file
103
Pods/ASIHTTPRequest/Classes/ASICacheDelegate.h
generated
Normal file
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// 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
|
42
Pods/ASIHTTPRequest/Classes/ASIDataCompressor.h
generated
Normal file
42
Pods/ASIHTTPRequest/Classes/ASIDataCompressor.h
generated
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// 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 (assign, readonly) BOOL streamReady;
|
||||
@end
|
219
Pods/ASIHTTPRequest/Classes/ASIDataCompressor.m
generated
Normal file
219
Pods/ASIHTTPRequest/Classes/ASIDataCompressor.m
generated
Normal file
|
@ -0,0 +1,219 @@
|
|||
//
|
||||
// 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;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_out == 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = [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 NO;
|
||||
}
|
||||
}
|
||||
|
||||
// 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] == NSStreamEventErrorOccurred) {
|
||||
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: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:[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
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 %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
41
Pods/ASIHTTPRequest/Classes/ASIDataDecompressor.h
generated
Normal file
41
Pods/ASIHTTPRequest/Classes/ASIDataDecompressor.h
generated
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// 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 (assign, readonly) BOOL streamReady;
|
||||
@end
|
218
Pods/ASIHTTPRequest/Classes/ASIDataDecompressor.m
generated
Normal file
218
Pods/ASIHTTPRequest/Classes/ASIDataDecompressor.m
generated
Normal file
|
@ -0,0 +1,218 @@
|
|||
//
|
||||
// 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;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_in != 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = [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] == NSStreamEventErrorOccurred) {
|
||||
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:readLength error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the inflated data out to the destination file
|
||||
[outputStream write:[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
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 %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
42
Pods/ASIHTTPRequest/Classes/ASIDownloadCache.h
generated
Normal file
42
Pods/ASIHTTPRequest/Classes/ASIDownloadCache.h
generated
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// 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;
|
||||
|
||||
@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
|
||||
@property (retain, nonatomic) NSString *storagePath;
|
||||
@property (retain) NSRecursiveLock *accessLock;
|
||||
@property (assign) BOOL shouldRespectCacheControlHeaders;
|
||||
@end
|
504
Pods/ASIHTTPRequest/Classes/ASIDownloadCache.m
generated
Normal file
504
Pods/ASIHTTPRequest/Classes/ASIDownloadCache.m
generated
Normal file
|
@ -0,0 +1,504 @@
|
|||
//
|
||||
// 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";
|
||||
|
||||
@interface ASIDownloadCache ()
|
||||
+ (NSString *)keyForURL:(NSURL *)url;
|
||||
- (NSString *)pathToFile:(NSString *)file;
|
||||
@end
|
||||
|
||||
@implementation ASIDownloadCache
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldRespectCacheControlHeaders:YES];
|
||||
[self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
|
||||
[self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)sharedCache
|
||||
{
|
||||
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
|
||||
{
|
||||
NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
|
||||
|
||||
// If we weren't given a custom max-age, lets look for one in the response headers
|
||||
if (!maxAge) {
|
||||
NSString *cacheControl = [[responseHeaders objectForKey:@"Cache-Control"] lowercaseString];
|
||||
if (cacheControl) {
|
||||
NSScanner *scanner = [NSScanner scannerWithString:cacheControl];
|
||||
[scanner scanUpToString:@"max-age" intoString:NULL];
|
||||
if ([scanner scanString:@"max-age" intoString:NULL]) {
|
||||
[scanner scanString:@"=" intoString:NULL];
|
||||
[scanner scanDouble:&maxAge];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 2612 says max-age must override any Expires header
|
||||
if (maxAge) {
|
||||
return [[NSDate date] addTimeInterval:maxAge];
|
||||
} else {
|
||||
NSString *expires = [responseHeaders objectForKey:@"Expires"];
|
||||
if (expires) {
|
||||
return [ASIHTTPRequest dateFromRFC1123String:expires];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (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 alloc] init] autorelease] copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
|
||||
}
|
||||
[[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 (![extension length]) {
|
||||
extension = @"html";
|
||||
}
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
|
||||
}
|
||||
|
||||
- (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 (![extension length]) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
+ (NSString *)keyForURL:(NSURL *)url
|
||||
{
|
||||
NSString *urlString = [url absoluteString];
|
||||
// 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];
|
||||
}
|
||||
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
|
76
Pods/ASIHTTPRequest/Classes/ASIFormDataRequest.h
generated
Normal file
76
Pods/ASIHTTPRequest/Classes/ASIFormDataRequest.h
generated
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// 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:(id)data 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:(id)data 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 (assign) ASIPostFormat postFormat;
|
||||
@property (assign) NSStringEncoding stringEncoding;
|
||||
@end
|
355
Pods/ASIHTTPRequest/Classes/ASIFormDataRequest.m
generated
Normal file
355
Pods/ASIHTTPRequest/Classes/ASIFormDataRequest.m
generated
Normal file
|
@ -0,0 +1,355 @@
|
|||
//
|
||||
// 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 (retain) NSMutableArray *postData;
|
||||
@property (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([(NSString *)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];
|
||||
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 (![self postData]) {
|
||||
[self setPostData:[NSMutableArray array]];
|
||||
}
|
||||
[[self postData] addObject:[NSDictionary dictionaryWithObjectsAndKeys:[value description],@"value",key,@"key",nil]];
|
||||
}
|
||||
|
||||
- (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:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
if (![self fileData]) {
|
||||
[self setFileData:[NSMutableArray array]];
|
||||
}
|
||||
|
||||
// If data is a path to a local file
|
||||
if ([data isKindOfClass:[NSString class]]) {
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:(NSString *)data isDirectory:&isDirectory];
|
||||
if (!fileExists || isDirectory) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",data],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 = [(NSString *)data 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:data];
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *fileInfo = [NSDictionary dictionaryWithObjectsAndKeys:data, @"data", contentType, @"contentType", fileName, @"fileName", key, @"key", nil];
|
||||
[[self fileData] addObject:fileInfo];
|
||||
}
|
||||
|
||||
|
||||
- (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";
|
||||
}
|
||||
|
||||
NSDictionary *fileInfo = [NSDictionary dictionaryWithObjectsAndKeys:data, @"data", contentType, @"contentType", fileName, @"fileName", key, @"key", nil];
|
||||
[[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
|
||||
NSLog(@"%@",[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]));
|
||||
|
||||
// Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
|
||||
NSString *stringBoundary = @"0xKhTmLbOuNdArY";
|
||||
|
||||
[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
|
||||
{
|
||||
[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
|
999
Pods/ASIHTTPRequest/Classes/ASIHTTPRequest.h
generated
Normal file
999
Pods/ASIHTTPRequest/Classes/ASIHTTPRequest.h
generated
Normal file
|
@ -0,0 +1,999 @@
|
|||
//
|
||||
// ASIHTTPRequest.h
|
||||
//
|
||||
// Created by Ben Copsey on 04/10/2007.
|
||||
// Copyright 2007-2011 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A guide to the main features is available at:
|
||||
// http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Portions are based on the ImageClient example from Apple:
|
||||
// See: http://developer.apple.com/samplecode/ImageClient/listing37.html
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <CFNetwork/CFNetwork.h>
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
||||
#import <UIKit/UIKit.h> // Necessary for background task support
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#import <stdio.h>
|
||||
#import "ASIHTTPRequestConfig.h"
|
||||
#import "ASIHTTPRequestDelegate.h"
|
||||
#import "ASIProgressDelegate.h"
|
||||
#import "ASICacheDelegate.h"
|
||||
|
||||
@class ASIDataDecompressor;
|
||||
|
||||
extern NSString *ASIHTTPRequestVersion;
|
||||
|
||||
// Make targeting different platforms more reliable
|
||||
// See: http://www.blumtnwerx.com/blog/2009/06/cross-sdk-code-hygiene-in-xcode/
|
||||
#ifndef __IPHONE_3_2
|
||||
#define __IPHONE_3_2 30200
|
||||
#endif
|
||||
#ifndef __IPHONE_4_0
|
||||
#define __IPHONE_4_0 40000
|
||||
#endif
|
||||
#ifndef __MAC_10_5
|
||||
#define __MAC_10_5 1050
|
||||
#endif
|
||||
#ifndef __MAC_10_6
|
||||
#define __MAC_10_6 1060
|
||||
#endif
|
||||
|
||||
typedef enum _ASIAuthenticationState {
|
||||
ASINoAuthenticationNeededYet = 0,
|
||||
ASIHTTPAuthenticationNeeded = 1,
|
||||
ASIProxyAuthenticationNeeded = 2
|
||||
} ASIAuthenticationState;
|
||||
|
||||
typedef enum _ASINetworkErrorType {
|
||||
ASIConnectionFailureErrorType = 1,
|
||||
ASIRequestTimedOutErrorType = 2,
|
||||
ASIAuthenticationErrorType = 3,
|
||||
ASIRequestCancelledErrorType = 4,
|
||||
ASIUnableToCreateRequestErrorType = 5,
|
||||
ASIInternalErrorWhileBuildingRequestType = 6,
|
||||
ASIInternalErrorWhileApplyingCredentialsType = 7,
|
||||
ASIFileManagementError = 8,
|
||||
ASITooMuchRedirectionErrorType = 9,
|
||||
ASIUnhandledExceptionError = 10,
|
||||
ASICompressionError = 11
|
||||
|
||||
} ASINetworkErrorType;
|
||||
|
||||
|
||||
// The error domain that all errors generated by ASIHTTPRequest use
|
||||
extern NSString* const NetworkRequestErrorDomain;
|
||||
|
||||
// You can use this number to throttle upload and download bandwidth in iPhone OS apps send or receive a large amount of data
|
||||
// This may help apps that might otherwise be rejected for inclusion into the app store for using excessive bandwidth
|
||||
// This number is not official, as far as I know there is no officially documented bandwidth limit
|
||||
extern unsigned long const ASIWWANBandwidthThrottleAmount;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
typedef void (^ASIBasicBlock)(void);
|
||||
typedef void (^ASIHeadersBlock)(NSDictionary *responseHeaders);
|
||||
typedef void (^ASISizeBlock)(long long size);
|
||||
typedef void (^ASIProgressBlock)(unsigned long long size, unsigned long long total);
|
||||
typedef void (^ASIDataBlock)(NSData *data);
|
||||
#endif
|
||||
|
||||
@interface ASIHTTPRequest : NSOperation <NSCopying> {
|
||||
|
||||
// The url for this operation, should include GET params in the query string where appropriate
|
||||
NSURL *url;
|
||||
|
||||
// Will always contain the original url used for making the request (the value of url can change when a request is redirected)
|
||||
NSURL *originalURL;
|
||||
|
||||
// Temporarily stores the url we are about to redirect to. Will be nil again when we do redirect
|
||||
NSURL *redirectURL;
|
||||
|
||||
// The delegate - will be notified of various changes in state via the ASIHTTPRequestDelegate protocol
|
||||
id <ASIHTTPRequestDelegate> delegate;
|
||||
|
||||
// Another delegate that is also notified of request status changes and progress updates
|
||||
// Generally, you won't use this directly, but ASINetworkQueue sets itself as the queue so it can proxy updates to its own delegates
|
||||
// NOTE: WILL BE RETAINED BY THE REQUEST
|
||||
id <ASIHTTPRequestDelegate, ASIProgressDelegate> queue;
|
||||
|
||||
// HTTP method to use (eg: GET / POST / PUT / DELETE / HEAD etc). Defaults to GET
|
||||
NSString *requestMethod;
|
||||
|
||||
// Request body - only used when the whole body is stored in memory (shouldStreamPostDataFromDisk is false)
|
||||
NSMutableData *postBody;
|
||||
|
||||
// gzipped request body used when shouldCompressRequestBody is YES
|
||||
NSData *compressedPostBody;
|
||||
|
||||
// When true, post body will be streamed from a file on disk, rather than loaded into memory at once (useful for large uploads)
|
||||
// Automatically set to true in ASIFormDataRequests when using setFile:forKey:
|
||||
BOOL shouldStreamPostDataFromDisk;
|
||||
|
||||
// Path to file used to store post body (when shouldStreamPostDataFromDisk is true)
|
||||
// You can set this yourself - useful if you want to PUT a file from local disk
|
||||
NSString *postBodyFilePath;
|
||||
|
||||
// Path to a temporary file used to store a deflated post body (when shouldCompressPostBody is YES)
|
||||
NSString *compressedPostBodyFilePath;
|
||||
|
||||
// Set to true when ASIHTTPRequest automatically created a temporary file containing the request body (when true, the file at postBodyFilePath will be deleted at the end of the request)
|
||||
BOOL didCreateTemporaryPostDataFile;
|
||||
|
||||
// Used when writing to the post body when shouldStreamPostDataFromDisk is true (via appendPostData: or appendPostDataFromFile:)
|
||||
NSOutputStream *postBodyWriteStream;
|
||||
|
||||
// Used for reading from the post body when sending the request
|
||||
NSInputStream *postBodyReadStream;
|
||||
|
||||
// Dictionary for custom HTTP request headers
|
||||
NSMutableDictionary *requestHeaders;
|
||||
|
||||
// Set to YES when the request header dictionary has been populated, used to prevent this happening more than once
|
||||
BOOL haveBuiltRequestHeaders;
|
||||
|
||||
// Will be populated with HTTP response headers from the server
|
||||
NSDictionary *responseHeaders;
|
||||
|
||||
// Can be used to manually insert cookie headers to a request, but it's more likely that sessionCookies will do this for you
|
||||
NSMutableArray *requestCookies;
|
||||
|
||||
// Will be populated with cookies
|
||||
NSArray *responseCookies;
|
||||
|
||||
// If use useCookiePersistence is true, network requests will present valid cookies from previous requests
|
||||
BOOL useCookiePersistence;
|
||||
|
||||
// If useKeychainPersistence is true, network requests will attempt to read credentials from the keychain, and will save them in the keychain when they are successfully presented
|
||||
BOOL useKeychainPersistence;
|
||||
|
||||
// If useSessionPersistence is true, network requests will save credentials and reuse for the duration of the session (until clearSession is called)
|
||||
BOOL useSessionPersistence;
|
||||
|
||||
// If allowCompressedResponse is true, requests will inform the server they can accept compressed data, and will automatically decompress gzipped responses. Default is true.
|
||||
BOOL allowCompressedResponse;
|
||||
|
||||
// If shouldCompressRequestBody is true, the request body will be gzipped. Default is false.
|
||||
// You will probably need to enable this feature on your webserver to make this work. Tested with apache only.
|
||||
BOOL shouldCompressRequestBody;
|
||||
|
||||
// When downloadDestinationPath is set, the result of this request will be downloaded to the file at this location
|
||||
// If downloadDestinationPath is not set, download data will be stored in memory
|
||||
NSString *downloadDestinationPath;
|
||||
|
||||
// The location that files will be downloaded to. Once a download is complete, files will be decompressed (if necessary) and moved to downloadDestinationPath
|
||||
NSString *temporaryFileDownloadPath;
|
||||
|
||||
// If the response is gzipped and shouldWaitToInflateCompressedResponses is NO, a file will be created at this path containing the inflated response as it comes in
|
||||
NSString *temporaryUncompressedDataDownloadPath;
|
||||
|
||||
// Used for writing data to a file when downloadDestinationPath is set
|
||||
NSOutputStream *fileDownloadOutputStream;
|
||||
|
||||
NSOutputStream *inflatedFileDownloadOutputStream;
|
||||
|
||||
// When the request fails or completes successfully, complete will be true
|
||||
BOOL complete;
|
||||
|
||||
// external "finished" indicator, subject of KVO notifications; updates after 'complete'
|
||||
BOOL finished;
|
||||
|
||||
// True if our 'cancel' selector has been called
|
||||
BOOL cancelled;
|
||||
|
||||
// If an error occurs, error will contain an NSError
|
||||
// If error code is = ASIConnectionFailureErrorType (1, Connection failure occurred) - inspect [[error userInfo] objectForKey:NSUnderlyingErrorKey] for more information
|
||||
NSError *error;
|
||||
|
||||
// Username and password used for authentication
|
||||
NSString *username;
|
||||
NSString *password;
|
||||
|
||||
// User-Agent for this request
|
||||
NSString *userAgent;
|
||||
|
||||
// Domain used for NTLM authentication
|
||||
NSString *domain;
|
||||
|
||||
// Username and password used for proxy authentication
|
||||
NSString *proxyUsername;
|
||||
NSString *proxyPassword;
|
||||
|
||||
// Domain used for NTLM proxy authentication
|
||||
NSString *proxyDomain;
|
||||
|
||||
// Delegate for displaying upload progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
|
||||
id <ASIProgressDelegate> uploadProgressDelegate;
|
||||
|
||||
// Delegate for displaying download progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
|
||||
id <ASIProgressDelegate> downloadProgressDelegate;
|
||||
|
||||
// Whether we've seen the headers of the response yet
|
||||
BOOL haveExaminedHeaders;
|
||||
|
||||
// Data we receive will be stored here. Data may be compressed unless allowCompressedResponse is false - you should use [request responseData] instead in most cases
|
||||
NSMutableData *rawResponseData;
|
||||
|
||||
// Used for sending and receiving data
|
||||
CFHTTPMessageRef request;
|
||||
NSInputStream *readStream;
|
||||
|
||||
// Used for authentication
|
||||
CFHTTPAuthenticationRef requestAuthentication;
|
||||
NSDictionary *requestCredentials;
|
||||
|
||||
// Used during NTLM authentication
|
||||
int authenticationRetryCount;
|
||||
|
||||
// Authentication scheme (Basic, Digest, NTLM)
|
||||
// If you are using Basic authentication and want to force ASIHTTPRequest to send an authorization header without waiting for a 401, you must set this to (NSString *)kCFHTTPAuthenticationSchemeBasic
|
||||
NSString *authenticationScheme;
|
||||
|
||||
// Realm for authentication when credentials are required
|
||||
NSString *authenticationRealm;
|
||||
|
||||
// When YES, ASIHTTPRequest will present a dialog allowing users to enter credentials when no-matching credentials were found for a server that requires authentication
|
||||
// The dialog will not be shown if your delegate responds to authenticationNeededForRequest:
|
||||
// Default is NO.
|
||||
BOOL shouldPresentAuthenticationDialog;
|
||||
|
||||
// When YES, ASIHTTPRequest will present a dialog allowing users to enter credentials when no-matching credentials were found for a proxy server that requires authentication
|
||||
// The dialog will not be shown if your delegate responds to proxyAuthenticationNeededForRequest:
|
||||
// Default is YES (basically, because most people won't want the hassle of adding support for authenticating proxies to their apps)
|
||||
BOOL shouldPresentProxyAuthenticationDialog;
|
||||
|
||||
// Used for proxy authentication
|
||||
CFHTTPAuthenticationRef proxyAuthentication;
|
||||
NSDictionary *proxyCredentials;
|
||||
|
||||
// Used during authentication with an NTLM proxy
|
||||
int proxyAuthenticationRetryCount;
|
||||
|
||||
// Authentication scheme for the proxy (Basic, Digest, NTLM)
|
||||
NSString *proxyAuthenticationScheme;
|
||||
|
||||
// Realm for proxy authentication when credentials are required
|
||||
NSString *proxyAuthenticationRealm;
|
||||
|
||||
// HTTP status code, eg: 200 = OK, 404 = Not found etc
|
||||
int responseStatusCode;
|
||||
|
||||
// Description of the HTTP status code
|
||||
NSString *responseStatusMessage;
|
||||
|
||||
// Size of the response
|
||||
unsigned long long contentLength;
|
||||
|
||||
// Size of the partially downloaded content
|
||||
unsigned long long partialDownloadSize;
|
||||
|
||||
// Size of the POST payload
|
||||
unsigned long long postLength;
|
||||
|
||||
// The total amount of downloaded data
|
||||
unsigned long long totalBytesRead;
|
||||
|
||||
// The total amount of uploaded data
|
||||
unsigned long long totalBytesSent;
|
||||
|
||||
// Last amount of data read (used for incrementing progress)
|
||||
unsigned long long lastBytesRead;
|
||||
|
||||
// Last amount of data sent (used for incrementing progress)
|
||||
unsigned long long lastBytesSent;
|
||||
|
||||
// This lock prevents the operation from being cancelled at an inopportune moment
|
||||
NSRecursiveLock *cancelledLock;
|
||||
|
||||
// Called on the delegate (if implemented) when the request starts. Default is requestStarted:
|
||||
SEL didStartSelector;
|
||||
|
||||
// Called on the delegate (if implemented) when the request receives response headers. Default is request:didReceiveResponseHeaders:
|
||||
SEL didReceiveResponseHeadersSelector;
|
||||
|
||||
// Called on the delegate (if implemented) when the request receives a Location header and shouldRedirect is YES
|
||||
// The delegate can then change the url if needed, and can restart the request by calling [request redirectToURL:], or simply cancel it
|
||||
SEL willRedirectSelector;
|
||||
|
||||
// Called on the delegate (if implemented) when the request completes successfully. Default is requestFinished:
|
||||
SEL didFinishSelector;
|
||||
|
||||
// Called on the delegate (if implemented) when the request fails. Default is requestFailed:
|
||||
SEL didFailSelector;
|
||||
|
||||
// Called on the delegate (if implemented) when the request receives data. Default is request:didReceiveData:
|
||||
// If you set this and implement the method in your delegate, you must handle the data yourself - ASIHTTPRequest will not populate responseData or write the data to downloadDestinationPath
|
||||
SEL didReceiveDataSelector;
|
||||
|
||||
// Used for recording when something last happened during the request, we will compare this value with the current date to time out requests when appropriate
|
||||
NSDate *lastActivityTime;
|
||||
|
||||
// Number of seconds to wait before timing out - default is 10
|
||||
NSTimeInterval timeOutSeconds;
|
||||
|
||||
// Will be YES when a HEAD request will handle the content-length before this request starts
|
||||
BOOL shouldResetUploadProgress;
|
||||
BOOL shouldResetDownloadProgress;
|
||||
|
||||
// Used by HEAD requests when showAccurateProgress is YES to preset the content-length for this request
|
||||
ASIHTTPRequest *mainRequest;
|
||||
|
||||
// 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
|
||||
// The default for requests is YES
|
||||
// Also see the comments in ASINetworkQueue.h
|
||||
BOOL showAccurateProgress;
|
||||
|
||||
// Used to ensure the progress indicator is only incremented once when showAccurateProgress = NO
|
||||
BOOL updatedProgress;
|
||||
|
||||
// Prevents the body of the post being built more than once (largely for subclasses)
|
||||
BOOL haveBuiltPostBody;
|
||||
|
||||
// Used internally, may reflect the size of the internal buffer used by CFNetwork
|
||||
// POST / PUT operations with body sizes greater than uploadBufferSize will not timeout unless more than uploadBufferSize bytes have been sent
|
||||
// Likely to be 32KB on iPhone 3.0, 128KB on Mac OS X Leopard and iPhone 2.2.x
|
||||
unsigned long long uploadBufferSize;
|
||||
|
||||
// Text encoding for responses that do not send a Content-Type with a charset value. Defaults to NSISOLatin1StringEncoding
|
||||
NSStringEncoding defaultResponseEncoding;
|
||||
|
||||
// The text encoding of the response, will be defaultResponseEncoding if the server didn't specify. Can't be set.
|
||||
NSStringEncoding responseEncoding;
|
||||
|
||||
// Tells ASIHTTPRequest not to delete partial downloads, and allows it to use an existing file to resume a download. Defaults to NO.
|
||||
BOOL allowResumeForFileDownloads;
|
||||
|
||||
// Custom user information associated with the request (not sent to the server)
|
||||
NSDictionary *userInfo;
|
||||
NSInteger tag;
|
||||
|
||||
// Use HTTP 1.0 rather than 1.1 (defaults to false)
|
||||
BOOL useHTTPVersionOne;
|
||||
|
||||
// When YES, requests will automatically redirect when they get a HTTP 30x header (defaults to YES)
|
||||
BOOL shouldRedirect;
|
||||
|
||||
// Used internally to tell the main loop we need to stop and retry with a new url
|
||||
BOOL needsRedirect;
|
||||
|
||||
// Incremented every time this request redirects. When it reaches 5, we give up
|
||||
int redirectCount;
|
||||
|
||||
// When NO, requests will not check the secure certificate is valid (use for self-signed certificates during development, DO NOT USE IN PRODUCTION) Default is YES
|
||||
BOOL validatesSecureCertificate;
|
||||
|
||||
// If not nil and the URL scheme is https, CFNetwork configured to supply a client certificate
|
||||
SecIdentityRef clientCertificateIdentity;
|
||||
NSArray *clientCertificates;
|
||||
|
||||
// Details on the proxy to use - you could set these yourself, but it's probably best to let ASIHTTPRequest detect the system proxy settings
|
||||
NSString *proxyHost;
|
||||
int proxyPort;
|
||||
|
||||
// ASIHTTPRequest will assume kCFProxyTypeHTTP if the proxy type could not be automatically determined
|
||||
// Set to kCFProxyTypeSOCKS if you are manually configuring a SOCKS proxy
|
||||
NSString *proxyType;
|
||||
|
||||
// URL for a PAC (Proxy Auto Configuration) file. If you want to set this yourself, it's probably best if you use a local file
|
||||
NSURL *PACurl;
|
||||
|
||||
// See ASIAuthenticationState values above. 0 == default == No authentication needed yet
|
||||
ASIAuthenticationState authenticationNeeded;
|
||||
|
||||
// When YES, ASIHTTPRequests will present credentials from the session store for requests to the same server before being asked for them
|
||||
// This avoids an extra round trip for requests after authentication has succeeded, which is much for efficient for authenticated requests with large bodies, or on slower connections
|
||||
// Set to NO to only present credentials when explicitly asked for them
|
||||
// This only affects credentials stored in the session cache when useSessionPersistence is YES. Credentials from the keychain are never presented unless the server asks for them
|
||||
// Default is YES
|
||||
// For requests using Basic authentication, set authenticationScheme to (NSString *)kCFHTTPAuthenticationSchemeBasic, and credentials can be sent on the very first request when shouldPresentCredentialsBeforeChallenge is YES
|
||||
BOOL shouldPresentCredentialsBeforeChallenge;
|
||||
|
||||
// YES when the request hasn't finished yet. Will still be YES even if the request isn't doing anything (eg it's waiting for delegate authentication). READ-ONLY
|
||||
BOOL inProgress;
|
||||
|
||||
// Used internally to track whether the stream is scheduled on the run loop or not
|
||||
// Bandwidth throttling can unschedule the stream to slow things down while a request is in progress
|
||||
BOOL readStreamIsScheduled;
|
||||
|
||||
// Set to allow a request to automatically retry itself on timeout
|
||||
// Default is zero - timeout will stop the request
|
||||
int numberOfTimesToRetryOnTimeout;
|
||||
|
||||
// The number of times this request has retried (when numberOfTimesToRetryOnTimeout > 0)
|
||||
int retryCount;
|
||||
|
||||
// Temporarily set to YES when a closed connection forces a retry (internally, this stops ASIHTTPRequest cleaning up a temporary post body)
|
||||
BOOL willRetryRequest;
|
||||
|
||||
// When YES, requests will keep the connection to the server alive for a while to allow subsequent requests to re-use it for a substantial speed-boost
|
||||
// Persistent connections will not be used if the server explicitly closes the connection
|
||||
// Default is YES
|
||||
BOOL shouldAttemptPersistentConnection;
|
||||
|
||||
// Number of seconds to keep an inactive persistent connection open on the client side
|
||||
// Default is 60
|
||||
// If we get a keep-alive header, this is this value is replaced with how long the server told us to keep the connection around
|
||||
// A future date is created from this and used for expiring the connection, this is stored in connectionInfo's expires value
|
||||
NSTimeInterval persistentConnectionTimeoutSeconds;
|
||||
|
||||
// Set to yes when an appropriate keep-alive header is found
|
||||
BOOL connectionCanBeReused;
|
||||
|
||||
// Stores information about the persistent connection that is currently in use.
|
||||
// It may contain:
|
||||
// * The id we set for a particular connection, incremented every time we want to specify that we need a new connection
|
||||
// * The date that connection should expire
|
||||
// * A host, port and scheme for the connection. These are used to determine whether that connection can be reused by a subsequent request (all must match the new request)
|
||||
// * An id for the request that is currently using the connection. This is used for determining if a connection is available or not (we store a number rather than a reference to the request so we don't need to hang onto a request until the connection expires)
|
||||
// * A reference to the stream that is currently using the connection. This is necessary because we need to keep the old stream open until we've opened a new one.
|
||||
// The stream will be closed + released either when another request comes to use the connection, or when the timer fires to tell the connection to expire
|
||||
NSMutableDictionary *connectionInfo;
|
||||
|
||||
// When set to YES, 301 and 302 automatic redirects will use the original method and and body, according to the HTTP 1.1 standard
|
||||
// Default is NO (to follow the behaviour of most browsers)
|
||||
BOOL shouldUseRFC2616RedirectBehaviour;
|
||||
|
||||
// Used internally to record when a request has finished downloading data
|
||||
BOOL downloadComplete;
|
||||
|
||||
// An ID that uniquely identifies this request - primarily used for debugging persistent connections
|
||||
NSNumber *requestID;
|
||||
|
||||
// Will be ASIHTTPRequestRunLoopMode for synchronous requests, NSDefaultRunLoopMode for all other requests
|
||||
NSString *runLoopMode;
|
||||
|
||||
// This timer checks up on the request every 0.25 seconds, and updates progress
|
||||
NSTimer *statusTimer;
|
||||
|
||||
// The download cache that will be used for this request (use [ASIHTTPRequest setDefaultCache:cache] to configure a default cache
|
||||
id <ASICacheDelegate> downloadCache;
|
||||
|
||||
// The cache policy that will be used for this request - See ASICacheDelegate.h for possible values
|
||||
ASICachePolicy cachePolicy;
|
||||
|
||||
// The cache storage policy that will be used for this request - See ASICacheDelegate.h for possible values
|
||||
ASICacheStoragePolicy cacheStoragePolicy;
|
||||
|
||||
// Will be true when the response was pulled from the cache rather than downloaded
|
||||
BOOL didUseCachedResponse;
|
||||
|
||||
// Set secondsToCache to use a custom time interval for expiring the response when it is stored in a cache
|
||||
NSTimeInterval secondsToCache;
|
||||
|
||||
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
||||
BOOL shouldContinueWhenAppEntersBackground;
|
||||
UIBackgroundTaskIdentifier backgroundTask;
|
||||
#endif
|
||||
|
||||
// When downloading a gzipped response, the request will use this helper object to inflate the response
|
||||
ASIDataDecompressor *dataDecompressor;
|
||||
|
||||
// Controls how responses with a gzipped encoding are inflated (decompressed)
|
||||
// When set to YES (This is the default):
|
||||
// * gzipped responses for requests without a downloadDestinationPath will be inflated only when [request responseData] / [request responseString] is called
|
||||
// * gzipped responses for requests with a downloadDestinationPath set will be inflated only when the request completes
|
||||
//
|
||||
// When set to NO
|
||||
// All requests will inflate the response as it comes in
|
||||
// * If the request has no downloadDestinationPath set, the raw (compressed) response is discarded and rawResponseData will contain the decompressed response
|
||||
// * If the request has a downloadDestinationPath, the raw response will be stored in temporaryFileDownloadPath as normal, the inflated response will be stored in temporaryUncompressedDataDownloadPath
|
||||
// Once the request completes successfully, the contents of temporaryUncompressedDataDownloadPath are moved into downloadDestinationPath
|
||||
//
|
||||
// Setting this to NO may be especially useful for users using ASIHTTPRequest in conjunction with a streaming parser, as it will allow partial gzipped responses to be inflated and passed on to the parser while the request is still running
|
||||
BOOL shouldWaitToInflateCompressedResponses;
|
||||
|
||||
// Will be YES if this is a request created behind the scenes to download a PAC file - these requests do not attempt to configure their own proxies
|
||||
BOOL isPACFileRequest;
|
||||
|
||||
// Used for downloading PAC files from http / https webservers
|
||||
ASIHTTPRequest *PACFileRequest;
|
||||
|
||||
// Used for asynchronously reading PAC files from file:// URLs
|
||||
NSInputStream *PACFileReadStream;
|
||||
|
||||
// Used for storing PAC data from file URLs as it is downloaded
|
||||
NSMutableData *PACFileData;
|
||||
|
||||
// Set to YES in startSynchronous. Currently used by proxy detection to download PAC files synchronously when appropriate
|
||||
BOOL isSynchronous;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
//block to execute when request starts
|
||||
ASIBasicBlock startedBlock;
|
||||
|
||||
//block to execute when headers are received
|
||||
ASIHeadersBlock headersReceivedBlock;
|
||||
|
||||
//block to execute when request completes successfully
|
||||
ASIBasicBlock completionBlock;
|
||||
|
||||
//block to execute when request fails
|
||||
ASIBasicBlock failureBlock;
|
||||
|
||||
//block for when bytes are received
|
||||
ASIProgressBlock bytesReceivedBlock;
|
||||
|
||||
//block for when bytes are sent
|
||||
ASIProgressBlock bytesSentBlock;
|
||||
|
||||
//block for when download size is incremented
|
||||
ASISizeBlock downloadSizeIncrementedBlock;
|
||||
|
||||
//block for when upload size is incremented
|
||||
ASISizeBlock uploadSizeIncrementedBlock;
|
||||
|
||||
//block for handling raw bytes received
|
||||
ASIDataBlock dataReceivedBlock;
|
||||
|
||||
//block for handling authentication
|
||||
ASIBasicBlock authenticationNeededBlock;
|
||||
|
||||
//block for handling proxy authentication
|
||||
ASIBasicBlock proxyAuthenticationNeededBlock;
|
||||
|
||||
//block for handling redirections, if you want to
|
||||
ASIBasicBlock requestRedirectedBlock;
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
// Should be an HTTP or HTTPS url, may include username and password if appropriate
|
||||
- (id)initWithURL:(NSURL *)newURL;
|
||||
|
||||
// Convenience constructor
|
||||
+ (id)requestWithURL:(NSURL *)newURL;
|
||||
|
||||
+ (id)requestWithURL:(NSURL *)newURL usingCache:(id <ASICacheDelegate>)cache;
|
||||
+ (id)requestWithURL:(NSURL *)newURL usingCache:(id <ASICacheDelegate>)cache andCachePolicy:(ASICachePolicy)policy;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
- (void)setStartedBlock:(ASIBasicBlock)aStartedBlock;
|
||||
- (void)setHeadersReceivedBlock:(ASIHeadersBlock)aReceivedBlock;
|
||||
- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock;
|
||||
- (void)setFailedBlock:(ASIBasicBlock)aFailedBlock;
|
||||
- (void)setBytesReceivedBlock:(ASIProgressBlock)aBytesReceivedBlock;
|
||||
- (void)setBytesSentBlock:(ASIProgressBlock)aBytesSentBlock;
|
||||
- (void)setDownloadSizeIncrementedBlock:(ASISizeBlock) aDownloadSizeIncrementedBlock;
|
||||
- (void)setUploadSizeIncrementedBlock:(ASISizeBlock) anUploadSizeIncrementedBlock;
|
||||
- (void)setDataReceivedBlock:(ASIDataBlock)aReceivedBlock;
|
||||
- (void)setAuthenticationNeededBlock:(ASIBasicBlock)anAuthenticationBlock;
|
||||
- (void)setProxyAuthenticationNeededBlock:(ASIBasicBlock)aProxyAuthenticationBlock;
|
||||
- (void)setRequestRedirectedBlock:(ASIBasicBlock)aRedirectBlock;
|
||||
#endif
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
// Add a custom header to the request
|
||||
- (void)addRequestHeader:(NSString *)header value:(NSString *)value;
|
||||
|
||||
// Called during buildRequestHeaders and after a redirect to create a cookie header from request cookies and the global store
|
||||
- (void)applyCookieHeader;
|
||||
|
||||
// Populate the request headers dictionary. Called before a request is started, or by a HEAD request that needs to borrow them
|
||||
- (void)buildRequestHeaders;
|
||||
|
||||
// Used to apply authorization header to a request before it is sent (when shouldPresentCredentialsBeforeChallenge is YES)
|
||||
- (void)applyAuthorizationHeader;
|
||||
|
||||
|
||||
// Create the post body
|
||||
- (void)buildPostBody;
|
||||
|
||||
// Called to add data to the post body. Will append to postBody when shouldStreamPostDataFromDisk is false, or write to postBodyWriteStream when true
|
||||
- (void)appendPostData:(NSData *)data;
|
||||
- (void)appendPostDataFromFile:(NSString *)file;
|
||||
|
||||
#pragma mark get information about this request
|
||||
|
||||
// Returns the contents of the result as an NSString (not appropriate for binary data - used responseData instead)
|
||||
- (NSString *)responseString;
|
||||
|
||||
// Response data, automatically uncompressed where appropriate
|
||||
- (NSData *)responseData;
|
||||
|
||||
// Returns true if the response was gzip compressed
|
||||
- (BOOL)isResponseCompressed;
|
||||
|
||||
#pragma mark running a request
|
||||
|
||||
|
||||
// Run a request synchronously, and return control when the request completes or fails
|
||||
- (void)startSynchronous;
|
||||
|
||||
// Run request in the background
|
||||
- (void)startAsynchronous;
|
||||
|
||||
// Clears all delegates and blocks, then cancels the request
|
||||
- (void)clearDelegatesAndCancel;
|
||||
|
||||
#pragma mark HEAD request
|
||||
|
||||
// Used by ASINetworkQueue to create a HEAD request appropriate for this request with the same headers (though you can use it yourself)
|
||||
- (ASIHTTPRequest *)HEADRequest;
|
||||
|
||||
#pragma mark upload/download progress
|
||||
|
||||
// Called approximately every 0.25 seconds to update the progress delegates
|
||||
- (void)updateProgressIndicators;
|
||||
|
||||
// Updates upload progress (notifies the queue and/or uploadProgressDelegate of this request)
|
||||
- (void)updateUploadProgress;
|
||||
|
||||
// Updates download progress (notifies the queue and/or uploadProgressDelegate of this request)
|
||||
- (void)updateDownloadProgress;
|
||||
|
||||
// Called when authorisation is needed, as we only find out we don't have permission to something when the upload is complete
|
||||
- (void)removeUploadProgressSoFar;
|
||||
|
||||
// Called when we get a content-length header and shouldResetDownloadProgress is true
|
||||
- (void)incrementDownloadSizeBy:(long long)length;
|
||||
|
||||
// Called when a request starts and shouldResetUploadProgress is true
|
||||
// Also called (with a negative length) to remove the size of the underlying buffer used for uploading
|
||||
- (void)incrementUploadSizeBy:(long long)length;
|
||||
|
||||
// Helper method for interacting with progress indicators to abstract the details of different APIS (NSProgressIndicator and UIProgressView)
|
||||
+ (void)updateProgressIndicator:(id *)indicator withProgress:(unsigned long long)progress ofTotal:(unsigned long long)total;
|
||||
|
||||
// Helper method used for performing invocations on the main thread (used for progress)
|
||||
+ (void)performSelector:(SEL)selector onTarget:(id *)target withObject:(id)object amount:(void *)amount callerToRetain:(id)caller;
|
||||
|
||||
#pragma mark talking to delegates
|
||||
|
||||
// Called when a request starts, lets the delegate know via didStartSelector
|
||||
- (void)requestStarted;
|
||||
|
||||
// Called when a request receives response headers, lets the delegate know via didReceiveResponseHeadersSelector
|
||||
- (void)requestReceivedResponseHeaders:(NSDictionary *)newHeaders;
|
||||
|
||||
// Called when a request completes successfully, lets the delegate know via didFinishSelector
|
||||
- (void)requestFinished;
|
||||
|
||||
// Called when a request fails, and lets the delegate know via didFailSelector
|
||||
- (void)failWithError:(NSError *)theError;
|
||||
|
||||
// Called to retry our request when our persistent connection is closed
|
||||
// Returns YES if we haven't already retried, and connection will be restarted
|
||||
// Otherwise, returns NO, and nothing will happen
|
||||
- (BOOL)retryUsingNewConnection;
|
||||
|
||||
// Can be called by delegates from inside their willRedirectSelector implementations to restart the request with a new url
|
||||
- (void)redirectToURL:(NSURL *)newURL;
|
||||
|
||||
#pragma mark parsing HTTP response headers
|
||||
|
||||
// Reads the response headers to find the content length, encoding, cookies for the session
|
||||
// Also initiates request redirection when shouldRedirect is true
|
||||
// And works out if HTTP auth is required
|
||||
- (void)readResponseHeaders;
|
||||
|
||||
// Attempts to set the correct encoding by looking at the Content-Type header, if this is one
|
||||
- (void)parseStringEncodingFromHeaders;
|
||||
|
||||
+ (void)parseMimeType:(NSString **)mimeType andResponseEncoding:(NSStringEncoding *)stringEncoding fromContentType:(NSString *)contentType;
|
||||
|
||||
#pragma mark http authentication stuff
|
||||
|
||||
// Apply credentials to this request
|
||||
- (BOOL)applyCredentials:(NSDictionary *)newCredentials;
|
||||
- (BOOL)applyProxyCredentials:(NSDictionary *)newCredentials;
|
||||
|
||||
// Attempt to obtain credentials for this request from the URL, username and password or keychain
|
||||
- (NSMutableDictionary *)findCredentials;
|
||||
- (NSMutableDictionary *)findProxyCredentials;
|
||||
|
||||
// Unlock (unpause) the request thread so it can resume the request
|
||||
// Should be called by delegates when they have populated the authentication information after an authentication challenge
|
||||
- (void)retryUsingSuppliedCredentials;
|
||||
|
||||
// Should be called by delegates when they wish to cancel authentication and stop
|
||||
- (void)cancelAuthentication;
|
||||
|
||||
// Apply authentication information and resume the request after an authentication challenge
|
||||
- (void)attemptToApplyCredentialsAndResume;
|
||||
- (void)attemptToApplyProxyCredentialsAndResume;
|
||||
|
||||
// Attempt to show the built-in authentication dialog, returns YES if credentials were supplied, NO if user cancelled dialog / dialog is disabled / running on main thread
|
||||
// Currently only used on iPhone OS
|
||||
- (BOOL)showProxyAuthenticationDialog;
|
||||
- (BOOL)showAuthenticationDialog;
|
||||
|
||||
// Construct a basic authentication header from the username and password supplied, and add it to the request headers
|
||||
// Used when shouldPresentCredentialsBeforeChallenge is YES
|
||||
- (void)addBasicAuthenticationHeaderWithUsername:(NSString *)theUsername andPassword:(NSString *)thePassword;
|
||||
|
||||
#pragma mark stream status handlers
|
||||
|
||||
// CFnetwork event handlers
|
||||
- (void)handleNetworkEvent:(CFStreamEventType)type;
|
||||
- (void)handleBytesAvailable;
|
||||
- (void)handleStreamComplete;
|
||||
- (void)handleStreamError;
|
||||
|
||||
#pragma mark cleanup
|
||||
|
||||
// Cleans up and lets the queue know this operation is finished.
|
||||
// Appears in this header for subclassing only, do not call this method from outside your request!
|
||||
- (void)markAsFinished;
|
||||
|
||||
// Cleans up temporary files. There's normally no reason to call these yourself, they are called automatically when a request completes or fails
|
||||
|
||||
// Clean up the temporary file used to store the downloaded data when it comes in (if downloadDestinationPath is set)
|
||||
- (BOOL)removeTemporaryDownloadFile;
|
||||
|
||||
// Clean up the temporary file used to store data that is inflated (decompressed) as it comes in
|
||||
- (BOOL)removeTemporaryUncompressedDownloadFile;
|
||||
|
||||
// Clean up the temporary file used to store the request body (when shouldStreamPostDataFromDisk is YES)
|
||||
- (BOOL)removeTemporaryUploadFile;
|
||||
|
||||
// Clean up the temporary file used to store a deflated (compressed) request body when shouldStreamPostDataFromDisk is YES
|
||||
- (BOOL)removeTemporaryCompressedUploadFile;
|
||||
|
||||
// Remove a file on disk, returning NO and populating the passed error pointer if it fails
|
||||
+ (BOOL)removeFileAtPath:(NSString *)path error:(NSError **)err;
|
||||
|
||||
#pragma mark persistent connections
|
||||
|
||||
// Get the ID of the connection this request used (only really useful in tests and debugging)
|
||||
- (NSNumber *)connectionID;
|
||||
|
||||
// Called automatically when a request is started to clean up any persistent connections that have expired
|
||||
+ (void)expirePersistentConnections;
|
||||
|
||||
#pragma mark default time out
|
||||
|
||||
+ (NSTimeInterval)defaultTimeOutSeconds;
|
||||
+ (void)setDefaultTimeOutSeconds:(NSTimeInterval)newTimeOutSeconds;
|
||||
|
||||
#pragma mark client certificate
|
||||
|
||||
- (void)setClientCertificateIdentity:(SecIdentityRef)anIdentity;
|
||||
|
||||
#pragma mark session credentials
|
||||
|
||||
+ (NSMutableArray *)sessionProxyCredentialsStore;
|
||||
+ (NSMutableArray *)sessionCredentialsStore;
|
||||
|
||||
+ (void)storeProxyAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials;
|
||||
+ (void)storeAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials;
|
||||
|
||||
+ (void)removeProxyAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials;
|
||||
+ (void)removeAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials;
|
||||
|
||||
- (NSDictionary *)findSessionProxyAuthenticationCredentials;
|
||||
- (NSDictionary *)findSessionAuthenticationCredentials;
|
||||
|
||||
#pragma mark keychain storage
|
||||
|
||||
// Save credentials for this request to the keychain
|
||||
- (void)saveCredentialsToKeychain:(NSDictionary *)newCredentials;
|
||||
|
||||
// Save credentials to the keychain
|
||||
+ (void)saveCredentials:(NSURLCredential *)credentials forHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
|
||||
+ (void)saveCredentials:(NSURLCredential *)credentials forProxy:(NSString *)host port:(int)port realm:(NSString *)realm;
|
||||
|
||||
// Return credentials from the keychain
|
||||
+ (NSURLCredential *)savedCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
|
||||
+ (NSURLCredential *)savedCredentialsForProxy:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
|
||||
|
||||
// Remove credentials from the keychain
|
||||
+ (void)removeCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
|
||||
+ (void)removeCredentialsForProxy:(NSString *)host port:(int)port realm:(NSString *)realm;
|
||||
|
||||
// We keep track of any cookies we accept, so that we can remove them from the persistent store later
|
||||
+ (void)setSessionCookies:(NSMutableArray *)newSessionCookies;
|
||||
+ (NSMutableArray *)sessionCookies;
|
||||
|
||||
// Adds a cookie to our list of cookies we've accepted, checking first for an old version of the same cookie and removing that
|
||||
+ (void)addSessionCookie:(NSHTTPCookie *)newCookie;
|
||||
|
||||
// Dump all session data (authentication and cookies)
|
||||
+ (void)clearSession;
|
||||
|
||||
#pragma mark get user agent
|
||||
|
||||
// Will be used as a user agent if requests do not specify a custom user agent
|
||||
// Is only used when you have specified a Bundle Display Name (CFDisplayBundleName) or Bundle Name (CFBundleName) in your plist
|
||||
+ (NSString *)defaultUserAgentString;
|
||||
+ (void)setDefaultUserAgentString:(NSString *)agent;
|
||||
|
||||
#pragma mark mime-type detection
|
||||
|
||||
// Return the mime type for a file
|
||||
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path;
|
||||
|
||||
#pragma mark bandwidth measurement / throttling
|
||||
|
||||
// The maximum number of bytes ALL requests can send / receive in a second
|
||||
// This is a rough figure. The actual amount used will be slightly more, this does not include HTTP headers
|
||||
+ (unsigned long)maxBandwidthPerSecond;
|
||||
+ (void)setMaxBandwidthPerSecond:(unsigned long)bytes;
|
||||
|
||||
// Get a rough average (for the last 5 seconds) of how much bandwidth is being used, in bytes
|
||||
+ (unsigned long)averageBandwidthUsedPerSecond;
|
||||
|
||||
- (void)performThrottling;
|
||||
|
||||
// Will return YES is bandwidth throttling is currently in use
|
||||
+ (BOOL)isBandwidthThrottled;
|
||||
|
||||
// Used internally to record bandwidth use, and by ASIInputStreams when uploading. It's probably best if you don't mess with this.
|
||||
+ (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes;
|
||||
|
||||
// On iPhone, ASIHTTPRequest can automatically turn throttling on and off as the connection type changes between WWAN and WiFi
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
// Set to YES to automatically turn on throttling when WWAN is connected, and automatically turn it off when it isn't
|
||||
+ (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle;
|
||||
|
||||
// Turns on throttling automatically when WWAN is connected using a custom limit, and turns it off automatically when it isn't
|
||||
+ (void)throttleBandwidthForWWANUsingLimit:(unsigned long)limit;
|
||||
|
||||
#pragma mark reachability
|
||||
|
||||
// Returns YES when an iPhone OS device is connected via WWAN, false when connected via WIFI or not connected
|
||||
+ (BOOL)isNetworkReachableViaWWAN;
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark queue
|
||||
|
||||
// Returns the shared queue
|
||||
+ (NSOperationQueue *)sharedQueue;
|
||||
|
||||
#pragma mark cache
|
||||
|
||||
+ (void)setDefaultCache:(id <ASICacheDelegate>)cache;
|
||||
+ (id <ASICacheDelegate>)defaultCache;
|
||||
|
||||
// Returns the maximum amount of data we can read as part of the current measurement period, and sleeps this thread if our allowance is used up
|
||||
+ (unsigned long)maxUploadReadLength;
|
||||
|
||||
#pragma mark network activity
|
||||
|
||||
+ (BOOL)isNetworkInUse;
|
||||
|
||||
+ (void)setShouldUpdateNetworkActivityIndicator:(BOOL)shouldUpdate;
|
||||
|
||||
// Shows the network activity spinner thing on iOS. You may wish to override this to do something else in Mac projects
|
||||
+ (void)showNetworkActivityIndicator;
|
||||
|
||||
// Hides the network activity spinner thing on iOS
|
||||
+ (void)hideNetworkActivityIndicator;
|
||||
|
||||
#pragma mark miscellany
|
||||
|
||||
// Used for generating Authorization header when using basic authentication when shouldPresentCredentialsBeforeChallenge is true
|
||||
// And also by ASIS3Request
|
||||
+ (NSString *)base64forData:(NSData *)theData;
|
||||
|
||||
// Returns a date from a string in RFC1123 format
|
||||
+ (NSDate *)dateFromRFC1123String:(NSString *)string;
|
||||
|
||||
|
||||
// Used for detecting multitasking support at runtime (for backgrounding requests)
|
||||
#if TARGET_OS_IPHONE
|
||||
+ (BOOL)isMultitaskingSupported;
|
||||
#endif
|
||||
|
||||
#pragma mark threading behaviour
|
||||
|
||||
// In the default implementation, all requests run in a single background thread
|
||||
// Advanced users only: Override this method in a subclass for a different threading behaviour
|
||||
// Eg: return [NSThread mainThread] to run all requests in the main thread
|
||||
// Alternatively, you can create a thread on demand, or manage a pool of threads
|
||||
// Threads returned by this method will need to run the runloop in default mode (eg CFRunLoopRun())
|
||||
// Requests will stop the runloop when they complete
|
||||
// If you have multiple requests sharing the thread you'll need to restart the runloop when this happens
|
||||
+ (NSThread *)threadForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
|
||||
#pragma mark ===
|
||||
|
||||
@property (retain) NSString *username;
|
||||
@property (retain) NSString *password;
|
||||
@property (retain) NSString *userAgent;
|
||||
@property (retain) NSString *domain;
|
||||
|
||||
@property (retain) NSString *proxyUsername;
|
||||
@property (retain) NSString *proxyPassword;
|
||||
@property (retain) NSString *proxyDomain;
|
||||
|
||||
@property (retain) NSString *proxyHost;
|
||||
@property (assign) int proxyPort;
|
||||
@property (retain) NSString *proxyType;
|
||||
|
||||
@property (retain,setter=setURL:, nonatomic) NSURL *url;
|
||||
@property (retain) NSURL *originalURL;
|
||||
@property (assign, nonatomic) id delegate;
|
||||
@property (retain, nonatomic) id queue;
|
||||
@property (assign, nonatomic) id uploadProgressDelegate;
|
||||
@property (assign, nonatomic) id downloadProgressDelegate;
|
||||
@property (assign) BOOL useKeychainPersistence;
|
||||
@property (assign) BOOL useSessionPersistence;
|
||||
@property (retain) NSString *downloadDestinationPath;
|
||||
@property (retain) NSString *temporaryFileDownloadPath;
|
||||
@property (retain) NSString *temporaryUncompressedDataDownloadPath;
|
||||
@property (assign) SEL didStartSelector;
|
||||
@property (assign) SEL didReceiveResponseHeadersSelector;
|
||||
@property (assign) SEL willRedirectSelector;
|
||||
@property (assign) SEL didFinishSelector;
|
||||
@property (assign) SEL didFailSelector;
|
||||
@property (assign) SEL didReceiveDataSelector;
|
||||
@property (retain,readonly) NSString *authenticationRealm;
|
||||
@property (retain,readonly) NSString *proxyAuthenticationRealm;
|
||||
@property (retain) NSError *error;
|
||||
@property (assign,readonly) BOOL complete;
|
||||
@property (retain) NSDictionary *responseHeaders;
|
||||
@property (retain) NSMutableDictionary *requestHeaders;
|
||||
@property (retain) NSMutableArray *requestCookies;
|
||||
@property (retain,readonly) NSArray *responseCookies;
|
||||
@property (assign) BOOL useCookiePersistence;
|
||||
@property (retain) NSDictionary *requestCredentials;
|
||||
@property (retain) NSDictionary *proxyCredentials;
|
||||
@property (assign,readonly) int responseStatusCode;
|
||||
@property (retain,readonly) NSString *responseStatusMessage;
|
||||
@property (retain) NSMutableData *rawResponseData;
|
||||
@property (assign) NSTimeInterval timeOutSeconds;
|
||||
@property (retain, nonatomic) NSString *requestMethod;
|
||||
@property (retain) NSMutableData *postBody;
|
||||
@property (assign) unsigned long long contentLength;
|
||||
@property (assign) unsigned long long postLength;
|
||||
@property (assign) BOOL shouldResetDownloadProgress;
|
||||
@property (assign) BOOL shouldResetUploadProgress;
|
||||
@property (assign) ASIHTTPRequest *mainRequest;
|
||||
@property (assign) BOOL showAccurateProgress;
|
||||
@property (assign) unsigned long long totalBytesRead;
|
||||
@property (assign) unsigned long long totalBytesSent;
|
||||
@property (assign) NSStringEncoding defaultResponseEncoding;
|
||||
@property (assign) NSStringEncoding responseEncoding;
|
||||
@property (assign) BOOL allowCompressedResponse;
|
||||
@property (assign) BOOL allowResumeForFileDownloads;
|
||||
@property (retain) NSDictionary *userInfo;
|
||||
@property (assign) NSInteger tag;
|
||||
@property (retain) NSString *postBodyFilePath;
|
||||
@property (assign) BOOL shouldStreamPostDataFromDisk;
|
||||
@property (assign) BOOL didCreateTemporaryPostDataFile;
|
||||
@property (assign) BOOL useHTTPVersionOne;
|
||||
@property (assign, readonly) unsigned long long partialDownloadSize;
|
||||
@property (assign) BOOL shouldRedirect;
|
||||
@property (assign) BOOL validatesSecureCertificate;
|
||||
@property (assign) BOOL shouldCompressRequestBody;
|
||||
@property (retain) NSURL *PACurl;
|
||||
@property (retain) NSString *authenticationScheme;
|
||||
@property (retain) NSString *proxyAuthenticationScheme;
|
||||
@property (assign) BOOL shouldPresentAuthenticationDialog;
|
||||
@property (assign) BOOL shouldPresentProxyAuthenticationDialog;
|
||||
@property (assign, readonly) ASIAuthenticationState authenticationNeeded;
|
||||
@property (assign) BOOL shouldPresentCredentialsBeforeChallenge;
|
||||
@property (assign, readonly) int authenticationRetryCount;
|
||||
@property (assign, readonly) int proxyAuthenticationRetryCount;
|
||||
@property (assign) BOOL haveBuiltRequestHeaders;
|
||||
@property (assign, nonatomic) BOOL haveBuiltPostBody;
|
||||
@property (assign, readonly) BOOL inProgress;
|
||||
@property (assign) int numberOfTimesToRetryOnTimeout;
|
||||
@property (assign, readonly) int retryCount;
|
||||
@property (assign) BOOL shouldAttemptPersistentConnection;
|
||||
@property (assign) NSTimeInterval persistentConnectionTimeoutSeconds;
|
||||
@property (assign) BOOL shouldUseRFC2616RedirectBehaviour;
|
||||
@property (assign, readonly) BOOL connectionCanBeReused;
|
||||
@property (retain, readonly) NSNumber *requestID;
|
||||
@property (assign) id <ASICacheDelegate> downloadCache;
|
||||
@property (assign) ASICachePolicy cachePolicy;
|
||||
@property (assign) ASICacheStoragePolicy cacheStoragePolicy;
|
||||
@property (assign, readonly) BOOL didUseCachedResponse;
|
||||
@property (assign) NSTimeInterval secondsToCache;
|
||||
@property (retain) NSArray *clientCertificates;
|
||||
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
||||
@property (assign) BOOL shouldContinueWhenAppEntersBackground;
|
||||
#endif
|
||||
@property (retain) ASIDataDecompressor *dataDecompressor;
|
||||
@property (assign) BOOL shouldWaitToInflateCompressedResponses;
|
||||
|
||||
@end
|
5060
Pods/ASIHTTPRequest/Classes/ASIHTTPRequest.m
generated
Normal file
5060
Pods/ASIHTTPRequest/Classes/ASIHTTPRequest.m
generated
Normal file
File diff suppressed because it is too large
Load diff
37
Pods/ASIHTTPRequest/Classes/ASIHTTPRequestConfig.h
generated
Normal file
37
Pods/ASIHTTPRequest/Classes/ASIHTTPRequestConfig.h
generated
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// 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
|
||||
// ======
|
||||
|
||||
// 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
|
35
Pods/ASIHTTPRequest/Classes/ASIHTTPRequestDelegate.h
generated
Normal file
35
Pods/ASIHTTPRequest/Classes/ASIHTTPRequestDelegate.h
generated
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// 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
|
26
Pods/ASIHTTPRequest/Classes/ASIInputStream.h
generated
Normal file
26
Pods/ASIHTTPRequest/Classes/ASIInputStream.h
generated
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// 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
|
136
Pods/ASIHTTPRequest/Classes/ASIInputStream.m
generated
Normal file
136
Pods/ASIHTTPRequest/Classes/ASIInputStream.m
generated
Normal file
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// 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];
|
||||
}
|
||||
[ASIHTTPRequest incrementBandwidthUsedInLastSecond:toRead];
|
||||
[readLock unlock];
|
||||
return [stream read:buffer maxLength:toRead];
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
108
Pods/ASIHTTPRequest/Classes/ASINetworkQueue.h
generated
Normal file
108
Pods/ASIHTTPRequest/Classes/ASINetworkQueue.h
generated
Normal file
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// 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) SEL requestDidStartSelector;
|
||||
@property (assign) SEL requestDidReceiveResponseHeadersSelector;
|
||||
@property (assign) SEL requestWillRedirectSelector;
|
||||
@property (assign) SEL requestDidFinishSelector;
|
||||
@property (assign) SEL requestDidFailSelector;
|
||||
@property (assign) SEL queueDidFinishSelector;
|
||||
@property (assign) BOOL shouldCancelAllRequestsOnFailure;
|
||||
@property (assign) id delegate;
|
||||
@property (assign) BOOL showAccurateProgress;
|
||||
@property (assign, readonly) int requestsCount;
|
||||
@property (retain) NSDictionary *userInfo;
|
||||
|
||||
@property (assign) unsigned long long bytesUploadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToUpload;
|
||||
@property (assign) unsigned long long bytesDownloadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToDownload;
|
||||
|
||||
@end
|
343
Pods/ASIHTTPRequest/Classes/ASINetworkQueue.m
generated
Normal file
343
Pods/ASIHTTPRequest/Classes/ASINetworkQueue.m
generated
Normal file
|
@ -0,0 +1,343 @@
|
|||
//
|
||||
// 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:[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]+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]+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]+newLength];
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToUpload:[self totalBytesToUpload]+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
|
38
Pods/ASIHTTPRequest/Classes/ASIProgressDelegate.h
generated
Normal file
38
Pods/ASIHTTPRequest/Classes/ASIProgressDelegate.h
generated
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// 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
|
80
Pods/ASIHTTPRequest/Classes/ASIWebPageRequest/ASIWebPageRequest.h
generated
Normal file
80
Pods/ASIHTTPRequest/Classes/ASIWebPageRequest/ASIWebPageRequest.h
generated
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ASIWebPageRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 29/06/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// This is an EXPERIMENTAL class - use at your own risk!
|
||||
// It is strongly recommend to set a downloadDestinationPath when using ASIWebPageRequest
|
||||
// Also, performance will be better if your ASIWebPageRequest has a downloadCache setup
|
||||
// Known issue: You cannot use startSychronous with an ASIWebPageRequest
|
||||
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <libxml/HTMLparser.h>
|
||||
#import <libxml/xmlsave.h>
|
||||
#import <libxml/xpath.h>
|
||||
#import <libxml/xpathInternals.h>
|
||||
|
||||
@class ASINetworkQueue;
|
||||
|
||||
// Used internally for storing what type of data we got from the server
|
||||
typedef enum _ASIWebContentType {
|
||||
ASINotParsedWebContentType = 0,
|
||||
ASIHTMLWebContentType = 1,
|
||||
ASICSSWebContentType = 2
|
||||
} ASIWebContentType;
|
||||
|
||||
// These correspond with the urlReplacementMode property of ASIWebPageRequest
|
||||
typedef enum _ASIURLReplacementMode {
|
||||
|
||||
// Don't modify html or css content at all
|
||||
ASIDontModifyURLs = 0,
|
||||
|
||||
// Replace external resources urls (images, stylesheets etc) with data uris, so their content is embdedded directly in the html/css
|
||||
ASIReplaceExternalResourcesWithData = 1,
|
||||
|
||||
// Replace external resource urls with the url of locally cached content
|
||||
// You must set the baseURL of a WebView / UIWebView to a file url pointing at the downloadDestinationPath of the main ASIWebPageRequest if you want to display your content
|
||||
// See the Mac or iPhone example projects for a demonstration of how to do this
|
||||
// The hrefs of all hyperlinks are changed to use absolute urls when using this mode
|
||||
ASIReplaceExternalResourcesWithLocalURLs = 2
|
||||
} ASIURLReplacementMode;
|
||||
|
||||
|
||||
|
||||
@interface ASIWebPageRequest : ASIHTTPRequest {
|
||||
|
||||
// Each ASIWebPageRequest for an HTML or CSS file creates its own internal queue to download external resources
|
||||
ASINetworkQueue *externalResourceQueue;
|
||||
|
||||
// This dictionary stores a list of external resources to download, along with their content-type data or a path to the data
|
||||
NSMutableDictionary *resourceList;
|
||||
|
||||
// Used internally for parsing HTML (with libxml)
|
||||
xmlDocPtr doc;
|
||||
|
||||
// If the response is an HTML or CSS file, this will be set so the content can be correctly parsed when it has finished fetching external resources
|
||||
ASIWebContentType webContentType;
|
||||
|
||||
// Stores a reference to the ASIWebPageRequest that created this request
|
||||
// Note that a parentRequest can also have a parent request because ASIWebPageRequests parse their contents to look for external resources recursively
|
||||
// For example, a request for an image can be created by a request for a stylesheet which was created by a request for a web page
|
||||
ASIWebPageRequest *parentRequest;
|
||||
|
||||
// Controls what ASIWebPageRequest does with external resources. See the notes above for more.
|
||||
ASIURLReplacementMode urlReplacementMode;
|
||||
}
|
||||
|
||||
// Will return a data URI that contains a base64 version of the content at this url
|
||||
// This is used when replacing urls in the html and css with actual data
|
||||
// If you subclass ASIWebPageRequest, you can override this function to return different content or a url pointing at another location
|
||||
- (NSString *)contentForExternalURL:(NSString *)theURL;
|
||||
|
||||
// Returns the location that a downloaded external resource's content will be stored in
|
||||
- (NSString *)cachePathForRequest:(ASIWebPageRequest *)theRequest;
|
||||
|
||||
|
||||
@property (retain, nonatomic) ASIWebPageRequest *parentRequest;
|
||||
@property (assign, nonatomic) ASIURLReplacementMode urlReplacementMode;
|
||||
@end
|
703
Pods/ASIHTTPRequest/Classes/ASIWebPageRequest/ASIWebPageRequest.m
generated
Normal file
703
Pods/ASIHTTPRequest/Classes/ASIWebPageRequest/ASIWebPageRequest.m
generated
Normal file
|
@ -0,0 +1,703 @@
|
|||
//
|
||||
// ASIWebPageRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 29/06/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// This is an EXPERIMENTAL class - use at your own risk!
|
||||
|
||||
#import "ASIWebPageRequest.h"
|
||||
#import "ASINetworkQueue.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
// An xPath query that controls the external resources ASIWebPageRequest will fetch
|
||||
// By default, it will fetch stylesheets, javascript files, images, frames, iframes, and html 5 video / audio
|
||||
static xmlChar *xpathExpr = (xmlChar *)"//link/@href|//a/@href|//script/@src|//img/@src|//frame/@src|//iframe/@src|//style|//*/@style|//source/@src|//video/@poster|//audio/@src";
|
||||
|
||||
static NSLock *xmlParsingLock = nil;
|
||||
static NSMutableArray *requestsUsingXMLParser = nil;
|
||||
|
||||
@interface ASIWebPageRequest ()
|
||||
- (void)readResourceURLs;
|
||||
- (void)updateResourceURLs;
|
||||
- (void)parseAsHTML;
|
||||
- (void)parseAsCSS;
|
||||
- (void)addURLToFetch:(NSString *)newURL;
|
||||
+ (NSArray *)CSSURLsFromString:(NSString *)string;
|
||||
- (NSString *)relativePathTo:(NSString *)destinationPath fromPath:(NSString *)sourcePath;
|
||||
|
||||
- (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue;
|
||||
- (void)externalResourceFetchSucceeded:(ASIHTTPRequest *)externalResourceRequest;
|
||||
- (void)externalResourceFetchFailed:(ASIHTTPRequest *)externalResourceRequest;
|
||||
|
||||
@property (retain, nonatomic) ASINetworkQueue *externalResourceQueue;
|
||||
@property (retain, nonatomic) NSMutableDictionary *resourceList;
|
||||
@end
|
||||
|
||||
@implementation ASIWebPageRequest
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIWebPageRequest class]) {
|
||||
xmlParsingLock = [[NSLock alloc] init];
|
||||
requestsUsingXMLParser = [[NSMutableArray alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[externalResourceQueue cancelAllOperations];
|
||||
[externalResourceQueue release];
|
||||
[resourceList release];
|
||||
[parentRequest release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// This is a bit of a hack
|
||||
// The role of this method in normal ASIHTTPRequests is to tell the queue we are done with the request, and perform some cleanup
|
||||
// We override it to stop that happening, and instead do that work in the bottom of finishedFetchingExternalResources:
|
||||
- (void)markAsFinished
|
||||
{
|
||||
}
|
||||
|
||||
// This method is normally responsible for telling delegates we are done, but it happens to be the most convenient place to parse the responses
|
||||
// Again, we call the super implementation in finishedFetchingExternalResources:, or here if this download was not an HTML or CSS file
|
||||
- (void)requestFinished
|
||||
{
|
||||
complete = NO;
|
||||
if ([self mainRequest] || [self didUseCachedResponse]) {
|
||||
[super requestFinished];
|
||||
[super markAsFinished];
|
||||
return;
|
||||
}
|
||||
webContentType = ASINotParsedWebContentType;
|
||||
NSString *contentType = [[[self responseHeaders] objectForKey:@"Content-Type"] lowercaseString];
|
||||
contentType = [[contentType componentsSeparatedByString:@";"] objectAtIndex:0];
|
||||
if ([contentType isEqualToString:@"text/html"] || [contentType isEqualToString:@"text/xhtml"] || [contentType isEqualToString:@"text/xhtml+xml"] || [contentType isEqualToString:@"application/xhtml+xml"]) {
|
||||
[self parseAsHTML];
|
||||
return;
|
||||
} else if ([contentType isEqualToString:@"text/css"]) {
|
||||
[self parseAsCSS];
|
||||
return;
|
||||
}
|
||||
[super requestFinished];
|
||||
[super markAsFinished];
|
||||
}
|
||||
|
||||
- (void)parseAsCSS
|
||||
{
|
||||
webContentType = ASICSSWebContentType;
|
||||
|
||||
NSString *responseCSS = nil;
|
||||
NSError *err = nil;
|
||||
if ([self downloadDestinationPath]) {
|
||||
responseCSS = [NSString stringWithContentsOfFile:[self downloadDestinationPath] encoding:[self responseEncoding] error:&err];
|
||||
} else {
|
||||
responseCSS = [self responseString];
|
||||
}
|
||||
if (err) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,err,NSUnderlyingErrorKey,nil]]];
|
||||
return;
|
||||
} else if (!responseCSS) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
NSArray *urls = [[self class] CSSURLsFromString:responseCSS];
|
||||
|
||||
[self setResourceList:[NSMutableDictionary dictionary]];
|
||||
|
||||
for (NSString *theURL in urls) {
|
||||
[self addURLToFetch:theURL];
|
||||
}
|
||||
if (![[self resourceList] count]) {
|
||||
[super requestFinished];
|
||||
[super markAsFinished];
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new request for every item in the queue
|
||||
[[self externalResourceQueue] cancelAllOperations];
|
||||
[self setExternalResourceQueue:[ASINetworkQueue queue]];
|
||||
[[self externalResourceQueue] setDelegate:self];
|
||||
[[self externalResourceQueue] setShowAccurateProgress:[self showAccurateProgress]];
|
||||
[[self externalResourceQueue] setQueueDidFinishSelector:@selector(finishedFetchingExternalResources:)];
|
||||
[[self externalResourceQueue] setRequestDidFinishSelector:@selector(externalResourceFetchSucceeded:)];
|
||||
[[self externalResourceQueue] setRequestDidFailSelector:@selector(externalResourceFetchFailed:)];
|
||||
for (NSString *theURL in [[self resourceList] keyEnumerator]) {
|
||||
ASIWebPageRequest *externalResourceRequest = [ASIWebPageRequest requestWithURL:[NSURL URLWithString:theURL relativeToURL:[self url]]];
|
||||
[externalResourceRequest setRequestHeaders:[self requestHeaders]];
|
||||
[externalResourceRequest setDownloadCache:[self downloadCache]];
|
||||
[externalResourceRequest setCachePolicy:[self cachePolicy]];
|
||||
[externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]];
|
||||
[externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]];
|
||||
[externalResourceRequest setParentRequest:self];
|
||||
[externalResourceRequest setUrlReplacementMode:[self urlReplacementMode]];
|
||||
[externalResourceRequest setShouldResetDownloadProgress:NO];
|
||||
[externalResourceRequest setDelegate:self];
|
||||
[externalResourceRequest setUploadProgressDelegate:self];
|
||||
[externalResourceRequest setDownloadProgressDelegate:self];
|
||||
if ([self downloadDestinationPath]) {
|
||||
[externalResourceRequest setDownloadDestinationPath:[self cachePathForRequest:externalResourceRequest]];
|
||||
}
|
||||
[[self externalResourceQueue] addOperation:externalResourceRequest];
|
||||
}
|
||||
[[self externalResourceQueue] go];
|
||||
}
|
||||
|
||||
- (const char *)encodingName
|
||||
{
|
||||
xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
|
||||
switch ([self responseEncoding])
|
||||
{
|
||||
case NSASCIIStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_ASCII;
|
||||
break;
|
||||
case NSJapaneseEUCStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_EUC_JP;
|
||||
break;
|
||||
case NSUTF8StringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_UTF8;
|
||||
break;
|
||||
case NSISOLatin1StringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_8859_1;
|
||||
break;
|
||||
case NSShiftJISStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_SHIFT_JIS;
|
||||
break;
|
||||
case NSISOLatin2StringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_8859_2;
|
||||
break;
|
||||
case NSISO2022JPStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_2022_JP;
|
||||
break;
|
||||
case NSUTF16BigEndianStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_UTF16BE;
|
||||
break;
|
||||
case NSUTF16LittleEndianStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_UTF16LE;
|
||||
break;
|
||||
case NSUTF32BigEndianStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_UCS4BE;
|
||||
break;
|
||||
case NSUTF32LittleEndianStringEncoding:
|
||||
encoding = XML_CHAR_ENCODING_UCS4LE;
|
||||
break;
|
||||
case NSNEXTSTEPStringEncoding:
|
||||
case NSSymbolStringEncoding:
|
||||
case NSNonLossyASCIIStringEncoding:
|
||||
case NSUnicodeStringEncoding:
|
||||
case NSMacOSRomanStringEncoding:
|
||||
case NSUTF32StringEncoding:
|
||||
default:
|
||||
encoding = XML_CHAR_ENCODING_ERROR;
|
||||
break;
|
||||
}
|
||||
return xmlGetCharEncodingName(encoding);
|
||||
}
|
||||
|
||||
- (void)parseAsHTML
|
||||
{
|
||||
webContentType = ASIHTMLWebContentType;
|
||||
|
||||
// Only allow parsing of a single document at a time
|
||||
[xmlParsingLock lock];
|
||||
|
||||
if (![requestsUsingXMLParser count]) {
|
||||
xmlInitParser();
|
||||
}
|
||||
[requestsUsingXMLParser addObject:self];
|
||||
|
||||
|
||||
/* Load XML document */
|
||||
if ([self downloadDestinationPath]) {
|
||||
doc = htmlReadFile([[self downloadDestinationPath] cStringUsingEncoding:NSUTF8StringEncoding], [self encodingName], HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
|
||||
} else {
|
||||
NSData *data = [self responseData];
|
||||
doc = htmlReadMemory([data bytes], (int)[data length], "", [self encodingName], HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
|
||||
}
|
||||
if (doc == NULL) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to parse reponse XML",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
|
||||
[self setResourceList:[NSMutableDictionary dictionary]];
|
||||
|
||||
// Populate the list of URLS to download
|
||||
[self readResourceURLs];
|
||||
|
||||
if ([self error] || ![[self resourceList] count]) {
|
||||
[requestsUsingXMLParser removeObject:self];
|
||||
xmlFreeDoc(doc);
|
||||
doc = NULL;
|
||||
}
|
||||
|
||||
[xmlParsingLock unlock];
|
||||
|
||||
if ([self error]) {
|
||||
return;
|
||||
} else if (![[self resourceList] count]) {
|
||||
[super requestFinished];
|
||||
[super markAsFinished];
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new request for every item in the queue
|
||||
[[self externalResourceQueue] cancelAllOperations];
|
||||
[self setExternalResourceQueue:[ASINetworkQueue queue]];
|
||||
[[self externalResourceQueue] setDelegate:self];
|
||||
[[self externalResourceQueue] setShowAccurateProgress:[self showAccurateProgress]];
|
||||
[[self externalResourceQueue] setQueueDidFinishSelector:@selector(finishedFetchingExternalResources:)];
|
||||
[[self externalResourceQueue] setRequestDidFinishSelector:@selector(externalResourceFetchSucceeded:)];
|
||||
[[self externalResourceQueue] setRequestDidFailSelector:@selector(externalResourceFetchFailed:)];
|
||||
for (NSString *theURL in [[self resourceList] keyEnumerator]) {
|
||||
ASIWebPageRequest *externalResourceRequest = [ASIWebPageRequest requestWithURL:[NSURL URLWithString:theURL relativeToURL:[self url]]];
|
||||
[externalResourceRequest setRequestHeaders:[self requestHeaders]];
|
||||
[externalResourceRequest setDownloadCache:[self downloadCache]];
|
||||
[externalResourceRequest setCachePolicy:[self cachePolicy]];
|
||||
[externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]];
|
||||
[externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]];
|
||||
[externalResourceRequest setParentRequest:self];
|
||||
[externalResourceRequest setUrlReplacementMode:[self urlReplacementMode]];
|
||||
[externalResourceRequest setShouldResetDownloadProgress:NO];
|
||||
[externalResourceRequest setDelegate:self];
|
||||
[externalResourceRequest setUploadProgressDelegate:self];
|
||||
[externalResourceRequest setDownloadProgressDelegate:self];
|
||||
if ([self downloadDestinationPath]) {
|
||||
[externalResourceRequest setDownloadDestinationPath:[self cachePathForRequest:externalResourceRequest]];
|
||||
}
|
||||
[[self externalResourceQueue] addOperation:externalResourceRequest];
|
||||
}
|
||||
[[self externalResourceQueue] go];
|
||||
}
|
||||
|
||||
- (void)externalResourceFetchSucceeded:(ASIHTTPRequest *)externalResourceRequest
|
||||
{
|
||||
NSString *originalPath = [[externalResourceRequest userInfo] objectForKey:@"Path"];
|
||||
NSMutableDictionary *requestResponse = [[self resourceList] objectForKey:originalPath];
|
||||
NSString *contentType = [[externalResourceRequest responseHeaders] objectForKey:@"Content-Type"];
|
||||
if (!contentType) {
|
||||
contentType = @"application/octet-stream";
|
||||
}
|
||||
[requestResponse setObject:contentType forKey:@"ContentType"];
|
||||
if ([self downloadDestinationPath]) {
|
||||
[requestResponse setObject:[externalResourceRequest downloadDestinationPath] forKey:@"DataPath"];
|
||||
} else {
|
||||
NSData *data = [externalResourceRequest responseData];
|
||||
if (data) {
|
||||
[requestResponse setObject:data forKey:@"Data"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)externalResourceFetchFailed:(ASIHTTPRequest *)externalResourceRequest
|
||||
{
|
||||
[self failWithError:[externalResourceRequest error]];
|
||||
}
|
||||
|
||||
- (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue
|
||||
{
|
||||
if ([self urlReplacementMode] != ASIDontModifyURLs) {
|
||||
if (webContentType == ASICSSWebContentType) {
|
||||
NSMutableString *parsedResponse;
|
||||
NSError *err = nil;
|
||||
if ([self downloadDestinationPath]) {
|
||||
parsedResponse = [NSMutableString stringWithContentsOfFile:[self downloadDestinationPath] encoding:[self responseEncoding] error:&err];
|
||||
} else {
|
||||
parsedResponse = [[[self responseString] mutableCopy] autorelease];
|
||||
}
|
||||
if (err) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to read response CSS from disk",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
if (![self error]) {
|
||||
for (NSString *resource in [[self resourceList] keyEnumerator]) {
|
||||
if ([parsedResponse rangeOfString:resource].location != NSNotFound) {
|
||||
NSString *newURL = [self contentForExternalURL:resource];
|
||||
if (newURL) {
|
||||
[parsedResponse replaceOccurrencesOfString:resource withString:newURL options:0 range:NSMakeRange(0, [parsedResponse length])];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([self downloadDestinationPath]) {
|
||||
[parsedResponse writeToFile:[self downloadDestinationPath] atomically:NO encoding:[self responseEncoding] error:&err];
|
||||
if (err) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to write response CSS to disk",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
[self setRawResponseData:(id)[parsedResponse dataUsingEncoding:[self responseEncoding]]];
|
||||
}
|
||||
} else {
|
||||
[xmlParsingLock lock];
|
||||
|
||||
[self updateResourceURLs];
|
||||
|
||||
if (![self error]) {
|
||||
|
||||
// We'll use the xmlsave API so we can strip the xml declaration
|
||||
xmlSaveCtxtPtr saveContext;
|
||||
|
||||
if ([self downloadDestinationPath]) {
|
||||
|
||||
// Truncate the file first
|
||||
[[[[NSFileManager alloc] init] autorelease] createFileAtPath:[self downloadDestinationPath] contents:nil attributes:nil];
|
||||
|
||||
saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:[self downloadDestinationPath]] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
|
||||
xmlSaveDoc(saveContext, doc);
|
||||
xmlSaveClose(saveContext);
|
||||
|
||||
} else {
|
||||
#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_5
|
||||
// xmlSaveToBuffer() is not implemented in the 10.5 version of libxml
|
||||
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
[[[[NSFileManager alloc] init] autorelease] createFileAtPath:tempPath contents:nil attributes:nil];
|
||||
saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:tempPath] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
|
||||
xmlSaveDoc(saveContext, doc);
|
||||
xmlSaveClose(saveContext);
|
||||
[self setRawResponseData:[NSMutableData dataWithContentsOfFile:tempPath]];
|
||||
#else
|
||||
xmlBufferPtr buffer = xmlBufferCreate();
|
||||
saveContext = xmlSaveToBuffer(buffer,NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
|
||||
xmlSaveDoc(saveContext, doc);
|
||||
xmlSaveClose(saveContext);
|
||||
[self setRawResponseData:[[[NSMutableData alloc] initWithBytes:buffer->content length:buffer->use] autorelease]];
|
||||
xmlBufferFree(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Strip the content encoding if the original response was gzipped
|
||||
if ([self isResponseCompressed]) {
|
||||
NSMutableDictionary *headers = [[[self responseHeaders] mutableCopy] autorelease];
|
||||
[headers removeObjectForKey:@"Content-Encoding"];
|
||||
[self setResponseHeaders:headers];
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
doc = nil;
|
||||
|
||||
[requestsUsingXMLParser removeObject:self];
|
||||
if (![requestsUsingXMLParser count]) {
|
||||
xmlCleanupParser();
|
||||
}
|
||||
[xmlParsingLock unlock];
|
||||
}
|
||||
}
|
||||
if (![self parentRequest]) {
|
||||
[[self class] updateProgressIndicator:&downloadProgressDelegate withProgress:contentLength ofTotal:contentLength];
|
||||
}
|
||||
|
||||
NSMutableDictionary *newHeaders = [[[self responseHeaders] mutableCopy] autorelease];
|
||||
[newHeaders removeObjectForKey:@"Content-Encoding"];
|
||||
[self setResponseHeaders:newHeaders];
|
||||
|
||||
// Write the parsed content back to the cache
|
||||
if ([self urlReplacementMode] != ASIDontModifyURLs) {
|
||||
[[self downloadCache] storeResponseForRequest:self maxAge:[self secondsToCache]];
|
||||
}
|
||||
|
||||
[super requestFinished];
|
||||
[super markAsFinished];
|
||||
}
|
||||
|
||||
- (void)readResourceURLs
|
||||
{
|
||||
// Create xpath evaluation context
|
||||
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
|
||||
if(xpathCtx == NULL) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to create new XPath context",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
|
||||
// Evaluate xpath expression
|
||||
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
||||
if(xpathObj == NULL) {
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
|
||||
// Now loop through our matches
|
||||
xmlNodeSetPtr nodes = xpathObj->nodesetval;
|
||||
|
||||
int size = (nodes) ? nodes->nodeNr : 0;
|
||||
int i;
|
||||
for(i = size - 1; i >= 0; i--) {
|
||||
assert(nodes->nodeTab[i]);
|
||||
NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]];
|
||||
NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]];
|
||||
|
||||
xmlChar *nodeValue = xmlNodeGetContent(nodes->nodeTab[i]);
|
||||
NSString *value = [NSString stringWithCString:(char *)nodeValue encoding:[self responseEncoding]];
|
||||
xmlFree(nodeValue);
|
||||
|
||||
// Our xpath query matched all <link> elements, but we're only interested in stylesheets
|
||||
// We do the work here rather than in the xPath query because the query is case-sensitive, and we want to match on 'stylesheet', 'StyleSHEEt' etc
|
||||
if ([[parentName lowercaseString] isEqualToString:@"link"]) {
|
||||
xmlChar *relAttribute = xmlGetNoNsProp(nodes->nodeTab[i]->parent,(xmlChar *)"rel");
|
||||
if (relAttribute) {
|
||||
NSString *rel = [NSString stringWithCString:(char *)relAttribute encoding:[self responseEncoding]];
|
||||
xmlFree(relAttribute);
|
||||
if ([[rel lowercaseString] isEqualToString:@"stylesheet"]) {
|
||||
[self addURLToFetch:value];
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the content of <style> tags and style attributes to find external image urls or external css files
|
||||
} else if ([[nodeName lowercaseString] isEqualToString:@"style"]) {
|
||||
NSArray *externalResources = [[self class] CSSURLsFromString:value];
|
||||
for (NSString *theURL in externalResources) {
|
||||
[self addURLToFetch:theURL];
|
||||
}
|
||||
|
||||
// Parse the content of <source src=""> tags (HTML 5 audio + video)
|
||||
// We explictly disable the download of files with .webm, .ogv and .ogg extensions, since it's highly likely they won't be useful to us
|
||||
} else if ([[parentName lowercaseString] isEqualToString:@"source"] || [[parentName lowercaseString] isEqualToString:@"audio"]) {
|
||||
NSString *fileExtension = [[value pathExtension] lowercaseString];
|
||||
if (![fileExtension isEqualToString:@"ogg"] && ![fileExtension isEqualToString:@"ogv"] && ![fileExtension isEqualToString:@"webm"]) {
|
||||
[self addURLToFetch:value];
|
||||
}
|
||||
|
||||
// For all other elements matched by our xpath query (except hyperlinks), add the content as an external url to fetch
|
||||
} else if (![[parentName lowercaseString] isEqualToString:@"a"]) {
|
||||
[self addURLToFetch:value];
|
||||
}
|
||||
if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) {
|
||||
nodes->nodeTab[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
xmlXPathFreeObject(xpathObj);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
}
|
||||
|
||||
- (void)addURLToFetch:(NSString *)newURL
|
||||
{
|
||||
// Get rid of any surrounding whitespace
|
||||
newURL = [newURL stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
// Don't attempt to fetch data URIs
|
||||
if ([newURL length] > 4) {
|
||||
if (![[[newURL substringToIndex:5] lowercaseString] isEqualToString:@"data:"]) {
|
||||
NSURL *theURL = [NSURL URLWithString:newURL relativeToURL:[self url]];
|
||||
if (theURL) {
|
||||
if (![[self resourceList] objectForKey:newURL]) {
|
||||
[[self resourceList] setObject:[NSMutableDictionary dictionary] forKey:newURL];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)updateResourceURLs
|
||||
{
|
||||
// Create xpath evaluation context
|
||||
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
|
||||
if(xpathCtx == NULL) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to create new XPath context",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
|
||||
// Evaluate xpath expression
|
||||
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
||||
if(xpathObj == NULL) {
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]];
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all the matches, replacing urls where nescessary
|
||||
xmlNodeSetPtr nodes = xpathObj->nodesetval;
|
||||
int size = (nodes) ? nodes->nodeNr : 0;
|
||||
int i;
|
||||
for(i = size - 1; i >= 0; i--) {
|
||||
assert(nodes->nodeTab[i]);
|
||||
NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]];
|
||||
NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]];
|
||||
|
||||
xmlChar *nodeValue = xmlNodeGetContent(nodes->nodeTab[i]);
|
||||
NSString *value = [NSString stringWithCString:(char *)nodeValue encoding:[self responseEncoding]];
|
||||
xmlFree(nodeValue);
|
||||
|
||||
// Replace external urls in <style> tags or in style attributes
|
||||
if ([[nodeName lowercaseString] isEqualToString:@"style"]) {
|
||||
NSArray *externalResources = [[self class] CSSURLsFromString:value];
|
||||
for (NSString *theURL in externalResources) {
|
||||
if ([value rangeOfString:theURL].location != NSNotFound) {
|
||||
NSString *newURL = [self contentForExternalURL:theURL];
|
||||
if (newURL) {
|
||||
value = [value stringByReplacingOccurrencesOfString:theURL withString:newURL];
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[value cStringUsingEncoding:[self responseEncoding]]);
|
||||
|
||||
// Replace relative hyperlinks with absolute ones, since we will need to set a local baseURL when loading this in a web view
|
||||
} else if ([self urlReplacementMode] == ASIReplaceExternalResourcesWithLocalURLs && [[parentName lowercaseString] isEqualToString:@"a"]) {
|
||||
NSString *newURL = [[NSURL URLWithString:value relativeToURL:[self url]] absoluteString];
|
||||
if (newURL) {
|
||||
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[newURL cStringUsingEncoding:[self responseEncoding]]);
|
||||
}
|
||||
|
||||
// Replace all other external resource urls
|
||||
} else {
|
||||
NSString *newURL = [self contentForExternalURL:value];
|
||||
if (newURL) {
|
||||
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[newURL cStringUsingEncoding:[self responseEncoding]]);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) {
|
||||
nodes->nodeTab[i] = NULL;
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpathObj);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
}
|
||||
|
||||
// The three methods below are responsible for forwarding delegate methods we want to handle to the parent request's approdiate delegate
|
||||
// Certain delegate methods are ignored (eg setProgress: / setDoubleValue: / setMaxValue:)
|
||||
- (BOOL)respondsToSelector:(SEL)selector
|
||||
{
|
||||
if ([self parentRequest]) {
|
||||
return [[self parentRequest] respondsToSelector:selector];
|
||||
}
|
||||
//Ok, now check for selectors we want to pass on to the delegate
|
||||
if (selector == @selector(requestStarted:) || selector == @selector(request:didReceiveResponseHeaders:) || selector == @selector(request:willRedirectToURL:) || selector == @selector(requestFinished:) || selector == @selector(requestFailed:) || selector == @selector(request:didReceiveData:) || selector == @selector(authenticationNeededForRequest:) || selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
return [delegate respondsToSelector:selector];
|
||||
} else if (selector == @selector(request:didReceiveBytes:) || selector == @selector(request:incrementDownloadSizeBy:)) {
|
||||
return [downloadProgressDelegate respondsToSelector:selector];
|
||||
} else if (selector == @selector(request:didSendBytes:) || selector == @selector(request:incrementUploadSizeBy:)) {
|
||||
return [uploadProgressDelegate respondsToSelector:selector];
|
||||
}
|
||||
return [super respondsToSelector:selector];
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
|
||||
{
|
||||
if ([self parentRequest]) {
|
||||
return [[self parentRequest] methodSignatureForSelector:selector];
|
||||
}
|
||||
if (selector == @selector(requestStarted:) || selector == @selector(request:didReceiveResponseHeaders:) || selector == @selector(request:willRedirectToURL:) || selector == @selector(requestFinished:) || selector == @selector(requestFailed:) || selector == @selector(request:didReceiveData:) || selector == @selector(authenticationNeededForRequest:) || selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
return [(id)delegate methodSignatureForSelector:selector];
|
||||
} else if (selector == @selector(request:didReceiveBytes:) || selector == @selector(request:incrementDownloadSizeBy:)) {
|
||||
return [(id)downloadProgressDelegate methodSignatureForSelector:selector];
|
||||
} else if (selector == @selector(request:didSendBytes:) || selector == @selector(request:incrementUploadSizeBy:)) {
|
||||
return [(id)uploadProgressDelegate methodSignatureForSelector:selector];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation
|
||||
{
|
||||
if ([self parentRequest]) {
|
||||
return [[self parentRequest] forwardInvocation:anInvocation];
|
||||
}
|
||||
SEL selector = [anInvocation selector];
|
||||
if (selector == @selector(requestStarted:) || selector == @selector(request:didReceiveResponseHeaders:) || selector == @selector(request:willRedirectToURL:) || selector == @selector(requestFinished:) || selector == @selector(requestFailed:) || selector == @selector(request:didReceiveData:) || selector == @selector(authenticationNeededForRequest:) || selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
[anInvocation invokeWithTarget:delegate];
|
||||
} else if (selector == @selector(request:didReceiveBytes:) || selector == @selector(request:incrementDownloadSizeBy:)) {
|
||||
[anInvocation invokeWithTarget:downloadProgressDelegate];
|
||||
} else if (selector == @selector(request:didSendBytes:) || selector == @selector(request:incrementUploadSizeBy:)) {
|
||||
[anInvocation invokeWithTarget:uploadProgressDelegate];
|
||||
}
|
||||
}
|
||||
|
||||
// A quick and dirty way to build a list of external resource urls from a css string
|
||||
+ (NSArray *)CSSURLsFromString:(NSString *)string
|
||||
{
|
||||
NSMutableArray *urls = [NSMutableArray array];
|
||||
NSScanner *scanner = [NSScanner scannerWithString:string];
|
||||
[scanner setCaseSensitive:NO];
|
||||
while (1) {
|
||||
NSString *theURL = nil;
|
||||
[scanner scanUpToString:@"url(" intoString:NULL];
|
||||
[scanner scanString:@"url(" intoString:NULL];
|
||||
[scanner scanUpToString:@")" intoString:&theURL];
|
||||
if (!theURL) {
|
||||
break;
|
||||
}
|
||||
// Remove any quotes or whitespace around the url
|
||||
theURL = [theURL stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
theURL = [theURL stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\"'"]];
|
||||
theURL = [theURL stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
[urls addObject:theURL];
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
// Returns a relative file path from sourcePath to destinationPath (eg ../../foo/bar.txt)
|
||||
- (NSString *)relativePathTo:(NSString *)destinationPath fromPath:(NSString *)sourcePath
|
||||
{
|
||||
NSArray *sourcePathComponents = [sourcePath pathComponents];
|
||||
NSArray *destinationPathComponents = [destinationPath pathComponents];
|
||||
NSUInteger i;
|
||||
NSString *newPath = @"";
|
||||
NSString *sourcePathComponent, *destinationPathComponent;
|
||||
for (i=0; i<[sourcePathComponents count]; i++) {
|
||||
sourcePathComponent = [sourcePathComponents objectAtIndex:i];
|
||||
if ([destinationPathComponents count] > i) {
|
||||
destinationPathComponent = [destinationPathComponents objectAtIndex:i];
|
||||
if (![sourcePathComponent isEqualToString:destinationPathComponent]) {
|
||||
NSUInteger i2;
|
||||
for (i2=i+1; i2<[sourcePathComponents count]; i2++) {
|
||||
newPath = [newPath stringByAppendingPathComponent:@".."];
|
||||
}
|
||||
newPath = [newPath stringByAppendingPathComponent:destinationPathComponent];
|
||||
for (i2=i+1; i2<[destinationPathComponents count]; i2++) {
|
||||
newPath = [newPath stringByAppendingPathComponent:[destinationPathComponents objectAtIndex:i2]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
- (NSString *)contentForExternalURL:(NSString *)theURL
|
||||
{
|
||||
if ([self urlReplacementMode] == ASIReplaceExternalResourcesWithLocalURLs) {
|
||||
NSString *resourcePath = [[resourceList objectForKey:theURL] objectForKey:@"DataPath"];
|
||||
return [self relativePathTo:resourcePath fromPath:[self downloadDestinationPath]];
|
||||
}
|
||||
NSData *data;
|
||||
if ([[resourceList objectForKey:theURL] objectForKey:@"DataPath"]) {
|
||||
data = [NSData dataWithContentsOfFile:[[resourceList objectForKey:theURL] objectForKey:@"DataPath"]];
|
||||
} else {
|
||||
data = [[resourceList objectForKey:theURL] objectForKey:@"Data"];
|
||||
}
|
||||
NSString *contentType = [[resourceList objectForKey:theURL] objectForKey:@"ContentType"];
|
||||
if (data && contentType) {
|
||||
NSString *dataURI = [NSString stringWithFormat:@"data:%@;base64,",contentType];
|
||||
dataURI = [dataURI stringByAppendingString:[ASIHTTPRequest base64forData:data]];
|
||||
return dataURI;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)cachePathForRequest:(ASIWebPageRequest *)theRequest
|
||||
{
|
||||
// If we're using a download cache (and its a good idea to do so when using ASIWebPageRequest), ask it for the location to store this file
|
||||
// This ends up being quite efficient, as we download directly to the cache
|
||||
if ([self downloadCache]) {
|
||||
return [[self downloadCache] pathToStoreCachedResponseDataForRequest:theRequest];
|
||||
|
||||
// This is a fallback for when we don't have a download cache - we store the external resource in a file in the temporary directory
|
||||
} else {
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
const char *cStr = [[[theRequest url] absoluteString] UTF8String];
|
||||
unsigned char result[16];
|
||||
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
|
||||
NSString *md5 = [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]];
|
||||
return [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[md5 stringByAppendingPathExtension:@"html"]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@synthesize externalResourceQueue;
|
||||
@synthesize resourceList;
|
||||
@synthesize parentRequest;
|
||||
@synthesize urlReplacementMode;
|
||||
@end
|
58
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesCDNRequest.h
generated
Normal file
58
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesCDNRequest.h
generated
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// ASICloudFilesCDNRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
@class ASICloudFilesContainerXMLParserDelegate;
|
||||
|
||||
@interface ASICloudFilesCDNRequest : ASICloudFilesRequest {
|
||||
NSString *accountName;
|
||||
NSString *containerName;
|
||||
ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
}
|
||||
|
||||
@property (retain) NSString *accountName;
|
||||
@property (retain) NSString *containerName;
|
||||
@property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
|
||||
// HEAD /<api version>/<account>/<container>
|
||||
// Response:
|
||||
// X-CDN-Enabled: True
|
||||
// X-CDN-URI: http://cdn.cloudfiles.mosso.com/c1234
|
||||
// X-CDN-TTL: 86400
|
||||
+ (id)containerInfoRequest:(NSString *)containerName;
|
||||
- (BOOL)cdnEnabled;
|
||||
- (NSString *)cdnURI;
|
||||
- (NSUInteger)cdnTTL;
|
||||
|
||||
|
||||
// GET /<api version>/<account>
|
||||
// limit, marker, format, enabled_only=true
|
||||
+ (id)listRequest;
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly;
|
||||
- (NSArray *)containers;
|
||||
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
// PUT operations against a Container are used to CDN-enable that Container.
|
||||
// Include an HTTP header of X-TTL to specify a custom TTL.
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl;
|
||||
// returns: - (NSString *)cdnURI;
|
||||
|
||||
// POST /<api version>/<account>/<container>
|
||||
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
|
||||
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
|
||||
// X-TTL: 86400
|
||||
// X-CDN-Enabled: True
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl;
|
||||
// returns: - (NSString *)cdnURI;
|
||||
|
||||
|
||||
@end
|
147
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesCDNRequest.m
generated
Normal file
147
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesCDNRequest.m
generated
Normal file
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// ASICloudFilesCDNRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesCDNRequest.h"
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesCDNRequest
|
||||
|
||||
@synthesize accountName, containerName, xmlParserDelegate;
|
||||
|
||||
+ (id)cdnRequestWithMethod:(NSString *)method query:(NSString *)query {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest cdnManagementURL], query];
|
||||
ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)cdnRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest cdnManagementURL], containerName];
|
||||
ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Container Info
|
||||
|
||||
+ (id)containerInfoRequest:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"HEAD" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (BOOL)cdnEnabled {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Cdn-Enabled"] boolValue];
|
||||
}
|
||||
|
||||
- (NSString *)cdnURI {
|
||||
return [[self responseHeaders] objectForKey:@"X-Cdn-Uri"];
|
||||
}
|
||||
|
||||
- (NSUInteger)cdnTTL {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Ttl"] intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - CDN Container Lists
|
||||
|
||||
+ (id)listRequest {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:@"?format=xml"];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly {
|
||||
NSString *query = @"?format=xml";
|
||||
|
||||
if (limit > 0) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
if (marker) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]];
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:query];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSArray *)containers {
|
||||
if (xmlParserDelegate.containerObjects) {
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
if (xmlParserDelegate == nil) {
|
||||
xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init];
|
||||
}
|
||||
|
||||
[parser setDelegate:xmlParserDelegate];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - CDN Enable Container
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
// PUT operations against a Container are used to CDN-enable that Container.
|
||||
// Include an HTTP header of X-TTL to specify a custom TTL.
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName];
|
||||
[request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark POST - Adjust CDN Attributes
|
||||
|
||||
// POST /<api version>/<account>/<container>
|
||||
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
|
||||
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
|
||||
// X-TTL: 86400
|
||||
// X-CDN-Enabled: True
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName];
|
||||
if (ttl > 0) {
|
||||
[request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]];
|
||||
}
|
||||
[request addRequestHeader:@"X-Cdn-Enabled" value:cdnEnabled ? @"True" : @"False"];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
-(void)dealloc {
|
||||
[accountName release];
|
||||
[containerName release];
|
||||
[xmlParserDelegate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
41
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainer.h
generated
Normal file
41
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainer.h
generated
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// ASICloudFilesContainer.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface ASICloudFilesContainer : NSObject {
|
||||
|
||||
// regular container attributes
|
||||
NSString *name;
|
||||
NSUInteger count;
|
||||
NSUInteger bytes;
|
||||
|
||||
// CDN container attributes
|
||||
BOOL cdnEnabled;
|
||||
NSUInteger ttl;
|
||||
NSString *cdnURL;
|
||||
BOOL logRetention;
|
||||
NSString *referrerACL;
|
||||
NSString *useragentACL;
|
||||
}
|
||||
|
||||
+ (id)container;
|
||||
|
||||
// regular container attributes
|
||||
@property (retain) NSString *name;
|
||||
@property (assign) NSUInteger count;
|
||||
@property (assign) NSUInteger bytes;
|
||||
|
||||
// CDN container attributes
|
||||
@property (assign) BOOL cdnEnabled;
|
||||
@property (assign) NSUInteger ttl;
|
||||
@property (retain) NSString *cdnURL;
|
||||
@property (assign) BOOL logRetention;
|
||||
@property (retain) NSString *referrerACL;
|
||||
@property (retain) NSString *useragentACL;
|
||||
|
||||
@end
|
28
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainer.m
generated
Normal file
28
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainer.m
generated
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// ASICloudFilesContainer.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainer.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainer
|
||||
|
||||
// regular container attributes
|
||||
@synthesize name, count, bytes;
|
||||
|
||||
// CDN container attributes
|
||||
@synthesize cdnEnabled, ttl, cdnURL, logRetention, referrerACL, useragentACL;
|
||||
|
||||
+ (id)container {
|
||||
ASICloudFilesContainer *container = [[[self alloc] init] autorelease];
|
||||
return container;
|
||||
}
|
||||
|
||||
-(void) dealloc {
|
||||
[name release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
43
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerRequest.h
generated
Normal file
43
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerRequest.h
generated
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// ASICloudFilesContainerRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
@class ASICloudFilesContainer, ASICloudFilesContainerXMLParserDelegate;
|
||||
|
||||
@interface ASICloudFilesContainerRequest : ASICloudFilesRequest {
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesContainer *currentObject;
|
||||
ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
}
|
||||
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesContainer *currentObject;
|
||||
@property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
// HEAD /<api version>/<account>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)accountInfoRequest;
|
||||
- (NSUInteger)containerCount;
|
||||
- (NSUInteger)bytesUsed;
|
||||
|
||||
// GET /<api version>/<account>/<container>
|
||||
// Create a request to list all containers
|
||||
+ (id)listRequest;
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker;
|
||||
- (NSArray *)containers;
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
+ (id)createContainerRequest:(NSString *)containerName;
|
||||
|
||||
// DELETE /<api version>/<account>/<container>
|
||||
+ (id)deleteContainerRequest:(NSString *)containerName;
|
||||
|
||||
@end
|
134
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerRequest.m
generated
Normal file
134
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerRequest.m
generated
Normal file
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// ASICloudFilesContainerRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainerRequest.h"
|
||||
#import "ASICloudFilesContainer.h"
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainerRequest
|
||||
|
||||
@synthesize currentElement, currentContent, currentObject;
|
||||
@synthesize xmlParserDelegate;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Constructors
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName queryString:(NSString *)queryString {
|
||||
NSString *urlString;
|
||||
if (containerName == nil) {
|
||||
urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest storageURL], queryString];
|
||||
} else {
|
||||
urlString = [NSString stringWithFormat:@"%@/%@%@", [ASICloudFilesRequest storageURL], containerName, queryString];
|
||||
}
|
||||
|
||||
ASICloudFilesContainerRequest *request = [[[ASICloudFilesContainerRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method queryString:(NSString *)queryString {
|
||||
return [ASICloudFilesContainerRequest storageRequestWithMethod:method containerName:nil queryString:queryString];
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method {
|
||||
return [ASICloudFilesContainerRequest storageRequestWithMethod:method queryString:@""];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Retrieve Container Count and Total Bytes Used
|
||||
|
||||
// HEAD /<api version>/<account>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)accountInfoRequest {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"HEAD"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSUInteger)containerCount {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Account-Container-Count"] intValue];
|
||||
}
|
||||
|
||||
- (NSUInteger)bytesUsed {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Account-Bytes-Used"] intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - Retrieve Container List
|
||||
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker {
|
||||
NSString *queryString = @"?format=xml";
|
||||
|
||||
if (limit > 0) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
if (marker != nil) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]];
|
||||
}
|
||||
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET" queryString:queryString];
|
||||
return request;
|
||||
}
|
||||
|
||||
// GET /<api version>/<account>/<container>
|
||||
// Create a request to list all containers
|
||||
+ (id)listRequest {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET"
|
||||
queryString:@"?format=xml"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSArray *)containers {
|
||||
if (xmlParserDelegate.containerObjects) {
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
if (xmlParserDelegate == nil) {
|
||||
xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init];
|
||||
}
|
||||
|
||||
[parser setDelegate:xmlParserDelegate];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - Create Container
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
+ (id)createContainerRequest:(NSString *)containerName {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"PUT" containerName:containerName queryString:@""];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark DELETE - Delete Container
|
||||
|
||||
// DELETE /<api version>/<account>/<container>
|
||||
+ (id)deleteContainerRequest:(NSString *)containerName {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"DELETE" containerName:containerName queryString:@""];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[xmlParserDelegate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
31
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.h
generated
Normal file
31
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.h
generated
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ASICloudFilesContainerXMLParserDelegate.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/10/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
|
||||
#import "ASINSXMLParserCompat.h"
|
||||
#endif
|
||||
|
||||
@class ASICloudFilesContainer;
|
||||
|
||||
@interface ASICloudFilesContainerXMLParserDelegate : NSObject <NSXMLParserDelegate> {
|
||||
|
||||
NSMutableArray *containerObjects;
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesContainer *currentObject;
|
||||
}
|
||||
|
||||
@property (retain) NSMutableArray *containerObjects;
|
||||
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesContainer *currentObject;
|
||||
|
||||
@end
|
72
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.m
generated
Normal file
72
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.m
generated
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// ASICloudFilesContainerXMLParserDelegate.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/10/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
#import "ASICloudFilesContainer.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainerXMLParserDelegate
|
||||
|
||||
@synthesize containerObjects, currentElement, currentContent, currentObject;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark XML Parser Delegate
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
|
||||
[self setCurrentElement:elementName];
|
||||
|
||||
if ([elementName isEqualToString:@"container"]) {
|
||||
[self setCurrentObject:[ASICloudFilesContainer container]];
|
||||
}
|
||||
[self setCurrentContent:@""];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||
|
||||
if ([elementName isEqualToString:@"name"]) {
|
||||
[self currentObject].name = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"count"]) {
|
||||
[self currentObject].count = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"bytes"]) {
|
||||
[self currentObject].bytes = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"cdn_enabled"]) {
|
||||
[self currentObject].cdnEnabled = [[self currentObject] isEqual:@"True"];
|
||||
} else if ([elementName isEqualToString:@"ttl"]) {
|
||||
[self currentObject].ttl = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"cdn_url"]) {
|
||||
[self currentObject].cdnURL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"log_retention"]) {
|
||||
[self currentObject].logRetention = [[self currentObject] isEqual:@"True"];
|
||||
} else if ([elementName isEqualToString:@"referrer_acl"]) {
|
||||
[self currentObject].referrerACL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"useragent_acl"]) {
|
||||
[self currentObject].useragentACL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"container"]) {
|
||||
// we're done with this container. time to move on to the next
|
||||
if (containerObjects == nil) {
|
||||
containerObjects = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[containerObjects addObject:currentObject];
|
||||
[self setCurrentObject:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[containerObjects release];
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
30
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObject.h
generated
Normal file
30
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObject.h
generated
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ASICloudFilesObject.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface ASICloudFilesObject : NSObject {
|
||||
NSString *name;
|
||||
NSString *hash;
|
||||
NSUInteger bytes;
|
||||
NSString *contentType;
|
||||
NSDate *lastModified;
|
||||
NSData *data;
|
||||
NSMutableDictionary *metadata;
|
||||
}
|
||||
|
||||
@property (retain) NSString *name;
|
||||
@property (retain) NSString *hash;
|
||||
@property (assign) NSUInteger bytes;
|
||||
@property (retain) NSString *contentType;
|
||||
@property (retain) NSDate *lastModified;
|
||||
@property (retain) NSData *data;
|
||||
@property (retain) NSMutableDictionary *metadata;
|
||||
|
||||
+ (id)object;
|
||||
|
||||
@end
|
29
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObject.m
generated
Normal file
29
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObject.m
generated
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// ASICloudFilesObject.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesObject.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesObject
|
||||
|
||||
@synthesize name, hash, bytes, contentType, lastModified, data, metadata;
|
||||
|
||||
+ (id)object {
|
||||
ASICloudFilesObject *object = [[[self alloc] init] autorelease];
|
||||
return object;
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
[name release];
|
||||
[hash release];
|
||||
[contentType release];
|
||||
[lastModified release];
|
||||
[data release];
|
||||
[metadata release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
71
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObjectRequest.h
generated
Normal file
71
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObjectRequest.h
generated
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// ASICloudFilesObjectRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
|
||||
#import "ASINSXMLParserCompat.h"
|
||||
#endif
|
||||
|
||||
@class ASICloudFilesObject;
|
||||
|
||||
@interface ASICloudFilesObjectRequest : ASICloudFilesRequest <NSXMLParserDelegate> {
|
||||
|
||||
|
||||
NSString *accountName;
|
||||
NSString *containerName;
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesObject *currentObject;
|
||||
NSMutableArray *objects;
|
||||
|
||||
}
|
||||
|
||||
@property (retain) NSString *accountName;
|
||||
@property (retain) NSString *containerName;
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesObject *currentObject;
|
||||
|
||||
|
||||
// HEAD /<api version>/<account>/<container>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)containerInfoRequest:(NSString *)containerName;
|
||||
- (NSUInteger)containerObjectCount;
|
||||
- (NSUInteger)containerBytesUsed;
|
||||
|
||||
// HEAD /<api version>/<account>/<container>/<object>
|
||||
// to get metadata
|
||||
+ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
- (NSArray *)objects;
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path;
|
||||
|
||||
// Conditional GET headers: If-Match • If-None-Match • If-Modified-Since • If-Unmodified-Since
|
||||
// HTTP Range header: “Range: bytes=0-5” • “Range: bytes=-5” • “Range: bytes=32-“
|
||||
+ (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
- (ASICloudFilesObject *)object;
|
||||
|
||||
// PUT /<api version>/<account>/<container>/<object>
|
||||
// PUT operations are used to write, or overwrite, an Object's metadata and content.
|
||||
// The Object can be created with custom metadata via HTTP headers identified with the “X-Object-Meta-” prefix.
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object;
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType objectData:(NSData *)objectData metadata:(NSDictionary *)metadata etag:(NSString *)etag;
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType file:(NSString *)filePath metadata:(NSDictionary *)metadata etag:(NSString *)etag;
|
||||
|
||||
// POST /<api version>/<account>/<container>/<object>
|
||||
// POST operations against an Object name are used to set and overwrite arbitrary key/value metadata. You cannot use the POST operation to change any of the Object's other headers such as Content-Type, ETag, etc. It is not used to upload storage Objects (see PUT).
|
||||
// A POST request will delete all existing metadata added with a previous PUT/POST.
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object;
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata;
|
||||
|
||||
// DELETE /<api version>/<account>/<container>/<object>
|
||||
+ (id)deleteObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
|
||||
@end
|
261
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObjectRequest.m
generated
Normal file
261
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObjectRequest.m
generated
Normal file
|
@ -0,0 +1,261 @@
|
|||
//
|
||||
// ASICloudFilesObjectRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesObjectRequest.h"
|
||||
#import "ASICloudFilesObject.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesObjectRequest
|
||||
|
||||
@synthesize currentElement, currentContent, currentObject;
|
||||
@synthesize accountName, containerName;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Constructors
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest storageURL], containerName];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName queryString:(NSString *)queryString {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@%@", [ASICloudFilesRequest storageURL], containerName, queryString];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@/%@", [ASICloudFilesRequest storageURL], containerName, objectPath];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Container Info
|
||||
|
||||
+ (id)containerInfoRequest:(NSString *)containerName {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"HEAD" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSUInteger)containerObjectCount {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Container-Object-Count"] intValue];
|
||||
}
|
||||
|
||||
- (NSUInteger)containerBytesUsed {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Container-Bytes-Used"] intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Object Info
|
||||
|
||||
+ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"HEAD" containerName:containerName objectPath:objectPath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - List Objects
|
||||
|
||||
+ (NSString *)queryStringWithContainer:(NSString *)container limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path {
|
||||
NSString *queryString = @"?format=xml";
|
||||
|
||||
if (limit && limit > 0) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
if (marker) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", [marker stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
if (path) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&path=%@", [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
|
||||
return queryString;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path {
|
||||
NSString *queryString = [ASICloudFilesObjectRequest queryStringWithContainer:containerName limit:limit marker:marker prefix:prefix path:path];
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"GET" containerName:containerName queryString:queryString];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName {
|
||||
return [ASICloudFilesObjectRequest listRequestWithContainer:containerName limit:0 marker:nil prefix:nil path:nil];
|
||||
}
|
||||
|
||||
- (NSArray *)objects {
|
||||
if (objects) {
|
||||
return objects;
|
||||
}
|
||||
objects = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
[parser setDelegate:self];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
return objects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - Retrieve Object
|
||||
|
||||
+ (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
return [ASICloudFilesObjectRequest storageRequestWithMethod:@"GET" containerName:containerName objectPath:objectPath];
|
||||
}
|
||||
|
||||
- (ASICloudFilesObject *)object {
|
||||
ASICloudFilesObject *object = [ASICloudFilesObject object];
|
||||
|
||||
NSString *path = [self url].path;
|
||||
NSRange range = [path rangeOfString:self.containerName];
|
||||
path = [path substringFromIndex:range.location + range.length + 1];
|
||||
|
||||
object.name = path;
|
||||
object.hash = [[self responseHeaders] objectForKey:@"ETag"];
|
||||
object.bytes = [[[self responseHeaders] objectForKey:@"Content-Length"] intValue];
|
||||
object.contentType = [[self responseHeaders] objectForKey:@"Content-Type"];
|
||||
object.lastModified = [[self responseHeaders] objectForKey:@"Last-Modified"];
|
||||
object.metadata = [[NSMutableDictionary alloc] init];
|
||||
|
||||
for (NSString *key in [[self responseHeaders] keyEnumerator]) {
|
||||
NSRange metaRange = [key rangeOfString:@"X-Object-Meta-"];
|
||||
if (metaRange.location == 0) {
|
||||
[object.metadata setObject:[[self responseHeaders] objectForKey:key] forKey:[key substringFromIndex:metaRange.length]];
|
||||
}
|
||||
}
|
||||
|
||||
object.data = [self responseData];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - Upload Object
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object {
|
||||
return [self putObjectRequestWithContainer:containerName objectPath:object.name contentType:object.contentType objectData:object.data metadata:object.metadata etag:nil];
|
||||
}
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType objectData:(NSData *)objectData metadata:(NSDictionary *)metadata etag:(NSString *)etag {
|
||||
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath];
|
||||
[request addRequestHeader:@"Content-Type" value:contentType];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
[request appendPostData:objectData];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType file:(NSString *)filePath metadata:(NSDictionary *)metadata etag:(NSString *)etag
|
||||
{
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath];
|
||||
[request addRequestHeader:@"Content-Type" value:contentType];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
[request setShouldStreamPostDataFromDisk:YES];
|
||||
[request setPostBodyFilePath:filePath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark POST - Set Object Metadata
|
||||
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object {
|
||||
return [self postObjectRequestWithContainer:containerName objectPath:object.name metadata:object.metadata];
|
||||
}
|
||||
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"POST" containerName:containerName objectPath:objectPath];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark DELETE - Delete Object
|
||||
|
||||
+ (id)deleteObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"DELETE" containerName:containerName objectPath:objectPath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark XML Parser Delegate
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
|
||||
[self setCurrentElement:elementName];
|
||||
|
||||
if ([elementName isEqualToString:@"object"]) {
|
||||
[self setCurrentObject:[ASICloudFilesObject object]];
|
||||
}
|
||||
[self setCurrentContent:@""];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||
if ([elementName isEqualToString:@"name"]) {
|
||||
[self currentObject].name = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"hash"]) {
|
||||
[self currentObject].hash = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"bytes"]) {
|
||||
[self currentObject].bytes = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"content_type"]) {
|
||||
[self currentObject].contentType = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"last_modified"]) {
|
||||
[self currentObject].lastModified = [self dateFromString:[self currentContent]];
|
||||
} else if ([elementName isEqualToString:@"object"]) {
|
||||
// we're done with this object. time to move on to the next
|
||||
[objects addObject:currentObject];
|
||||
[self setCurrentObject:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[accountName release];
|
||||
[containerName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
40
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesRequest.h
generated
Normal file
40
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesRequest.h
generated
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// ASICloudFilesRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Michael Mayo on 22/12/09.
|
||||
// mike.mayo@rackspace.com or mike@overhrd.com
|
||||
// twitter.com/greenisus
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A class for accessing data stored on the Rackspace Cloud Files Service
|
||||
// http://www.rackspacecloud.com/cloud_hosting_products/files
|
||||
//
|
||||
// Cloud Files Developer Guide:
|
||||
// http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
|
||||
@interface ASICloudFilesRequest : ASIHTTPRequest {
|
||||
}
|
||||
|
||||
+ (NSString *)storageURL;
|
||||
+ (NSString *)cdnManagementURL;
|
||||
+ (NSString *)authToken;
|
||||
|
||||
#pragma mark Rackspace Cloud Authentication
|
||||
|
||||
+ (id)authenticationRequest;
|
||||
+ (NSError *)authenticate;
|
||||
+ (NSString *)username;
|
||||
+ (void)setUsername:(NSString *)username;
|
||||
+ (NSString *)apiKey;
|
||||
+ (void)setApiKey:(NSString *)apiKey;
|
||||
|
||||
// helper to parse dates in the format returned by Cloud Files
|
||||
-(NSDate *)dateFromString:(NSString *)dateString;
|
||||
|
||||
|
||||
@end
|
123
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesRequest.m
generated
Normal file
123
Pods/ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesRequest.m
generated
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// ASICloudFilesRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Michael Mayo on 22/12/09.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A class for accessing data stored on Rackspace's Cloud Files Service
|
||||
// http://www.rackspacecloud.com/cloud_hosting_products/files
|
||||
//
|
||||
// Cloud Files Developer Guide:
|
||||
// http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
static NSString *username = nil;
|
||||
static NSString *apiKey = nil;
|
||||
static NSString *authToken = nil;
|
||||
static NSString *storageURL = nil;
|
||||
static NSString *cdnManagementURL = nil;
|
||||
static NSString *rackspaceCloudAuthURL = @"https://auth.api.rackspacecloud.com/v1.0";
|
||||
|
||||
static NSRecursiveLock *accessDetailsLock = nil;
|
||||
|
||||
@implementation ASICloudFilesRequest
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASICloudFilesRequest class]) {
|
||||
accessDetailsLock = [[NSRecursiveLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Attributes and Service URLs
|
||||
|
||||
+ (NSString *)authToken {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
+ (NSString *)storageURL {
|
||||
return storageURL;
|
||||
}
|
||||
|
||||
+ (NSString *)cdnManagementURL {
|
||||
return cdnManagementURL;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Authentication
|
||||
|
||||
+ (id)authenticationRequest
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]] autorelease];
|
||||
[request addRequestHeader:@"X-Auth-User" value:username];
|
||||
[request addRequestHeader:@"X-Auth-Key" value:apiKey];
|
||||
[accessDetailsLock unlock];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (NSError *)authenticate
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
ASIHTTPRequest *request = [ASICloudFilesRequest authenticationRequest];
|
||||
[request startSynchronous];
|
||||
|
||||
if (![request error]) {
|
||||
NSDictionary *responseHeaders = [request responseHeaders];
|
||||
authToken = [responseHeaders objectForKey:@"X-Auth-Token"];
|
||||
storageURL = [responseHeaders objectForKey:@"X-Storage-Url"];
|
||||
cdnManagementURL = [responseHeaders objectForKey:@"X-Cdn-Management-Url"];
|
||||
}
|
||||
[accessDetailsLock unlock];
|
||||
return [request error];
|
||||
}
|
||||
|
||||
+ (NSString *)username
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
+ (void)setUsername:(NSString *)newUsername
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
[username release];
|
||||
username = [newUsername retain];
|
||||
[accessDetailsLock unlock];
|
||||
}
|
||||
|
||||
+ (NSString *)apiKey {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
+ (void)setApiKey:(NSString *)newApiKey
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
[apiKey release];
|
||||
apiKey = [newApiKey retain];
|
||||
[accessDetailsLock unlock];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Date Parser
|
||||
|
||||
-(NSDate *)dateFromString:(NSString *)dateString
|
||||
{
|
||||
// We store our date formatter in the calling thread's dictionary
|
||||
// NSDateFormatter is not thread-safe, this approach ensures each formatter is only used on a single thread
|
||||
// This formatter can be reused many times in parsing a single response, so it would be expensive to keep creating new date formatters
|
||||
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
|
||||
NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASICloudFilesResponseDateFormatter"];
|
||||
if (dateFormatter == nil) {
|
||||
dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
|
||||
// example: 2009-11-04T19:46:20.192723
|
||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'H:mm:ss.SSSSSS"];
|
||||
[threadDict setObject:dateFormatter forKey:@"ASICloudFilesResponseDateFormatter"];
|
||||
}
|
||||
return [dateFormatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
@end
|
23
Pods/ASIHTTPRequest/Classes/S3/ASINSXMLParserCompat.h
generated
Normal file
23
Pods/ASIHTTPRequest/Classes/S3/ASINSXMLParserCompat.h
generated
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// ASINSXMLParserCompat.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
// This file exists to prevent warnings about the NSXMLParserDelegate protocol when building S3 or Cloud Files stuff
|
||||
//
|
||||
// Created by Ben Copsey on 17/06/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0)
|
||||
@protocol NSXMLParserDelegate
|
||||
|
||||
@optional
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
34
Pods/ASIHTTPRequest/Classes/S3/ASIS3Bucket.h
generated
Normal file
34
Pods/ASIHTTPRequest/Classes/S3/ASIS3Bucket.h
generated
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// ASIS3Bucket.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// Instances of this class represent buckets stored on S3
|
||||
// ASIS3ServiceRequests return an array of ASIS3Buckets when you perform a service GET query
|
||||
// You'll probably never need to create instances of ASIS3Bucket yourself
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface ASIS3Bucket : NSObject {
|
||||
|
||||
// The name of this bucket (will be unique throughout S3)
|
||||
NSString *name;
|
||||
|
||||
// The date this bucket was created
|
||||
NSDate *creationDate;
|
||||
|
||||
// Information about the owner of this bucket
|
||||
NSString *ownerID;
|
||||
NSString *ownerName;
|
||||
}
|
||||
|
||||
+ (id)bucketWithOwnerID:(NSString *)ownerID ownerName:(NSString *)ownerName;
|
||||
|
||||
@property (retain) NSString *name;
|
||||
@property (retain) NSDate *creationDate;
|
||||
@property (retain) NSString *ownerID;
|
||||
@property (retain) NSString *ownerName;
|
||||
@end
|
32
Pods/ASIHTTPRequest/Classes/S3/ASIS3Bucket.m
generated
Normal file
32
Pods/ASIHTTPRequest/Classes/S3/ASIS3Bucket.m
generated
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// ASIS3Bucket.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3Bucket.h"
|
||||
|
||||
|
||||
@implementation ASIS3Bucket
|
||||
|
||||
+ (id)bucketWithOwnerID:(NSString *)anOwnerID ownerName:(NSString *)anOwnerName
|
||||
{
|
||||
ASIS3Bucket *bucket = [[[self alloc] init] autorelease];
|
||||
[bucket setOwnerID:anOwnerID];
|
||||
[bucket setOwnerName:anOwnerName];
|
||||
return bucket;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"Name: %@ creationDate: %@ ownerID: %@ ownerName: %@",[self name],[self creationDate],[self ownerID],[self ownerName]];
|
||||
}
|
||||
|
||||
|
||||
@synthesize name;
|
||||
@synthesize creationDate;
|
||||
@synthesize ownerID;
|
||||
@synthesize ownerName;
|
||||
@end
|
54
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketObject.h
generated
Normal file
54
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketObject.h
generated
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// ASIS3BucketObject.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/07/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// Instances of this class represent objects stored in a bucket on S3
|
||||
// ASIS3BucketRequests return an array of ASIS3BucketObjects when you perform a list query
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ASIS3ObjectRequest;
|
||||
|
||||
@interface ASIS3BucketObject : NSObject <NSCopying> {
|
||||
|
||||
// The bucket this object belongs to
|
||||
NSString *bucket;
|
||||
|
||||
// The key (path) of this object in the bucket
|
||||
NSString *key;
|
||||
|
||||
// When this object was last modified
|
||||
NSDate *lastModified;
|
||||
|
||||
// The ETag for this object's content
|
||||
NSString *ETag;
|
||||
|
||||
// The size in bytes of this object
|
||||
unsigned long long size;
|
||||
|
||||
// Info about the owner
|
||||
NSString *ownerID;
|
||||
NSString *ownerName;
|
||||
}
|
||||
|
||||
+ (id)objectWithBucket:(NSString *)bucket;
|
||||
|
||||
// Returns a request that will fetch this object when run
|
||||
- (ASIS3ObjectRequest *)GETRequest;
|
||||
|
||||
// Returns a request that will replace this object with the contents of the file at filePath when run
|
||||
- (ASIS3ObjectRequest *)PUTRequestWithFile:(NSString *)filePath;
|
||||
|
||||
// Returns a request that will delete this object when run
|
||||
- (ASIS3ObjectRequest *)DELETERequest;
|
||||
|
||||
@property (retain) NSString *bucket;
|
||||
@property (retain) NSString *key;
|
||||
@property (retain) NSDate *lastModified;
|
||||
@property (retain) NSString *ETag;
|
||||
@property (assign) unsigned long long size;
|
||||
@property (retain) NSString *ownerID;
|
||||
@property (retain) NSString *ownerName;
|
||||
@end
|
74
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketObject.m
generated
Normal file
74
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketObject.m
generated
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// ASIS3BucketObject.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/07/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3BucketObject.h"
|
||||
#import "ASIS3ObjectRequest.h"
|
||||
|
||||
@implementation ASIS3BucketObject
|
||||
|
||||
+ (id)objectWithBucket:(NSString *)theBucket
|
||||
{
|
||||
ASIS3BucketObject *object = [[[self alloc] init] autorelease];
|
||||
[object setBucket:theBucket];
|
||||
return object;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[bucket release];
|
||||
[key release];
|
||||
[lastModified release];
|
||||
[ETag release];
|
||||
[ownerID release];
|
||||
[ownerName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (ASIS3ObjectRequest *)GETRequest
|
||||
{
|
||||
return [ASIS3ObjectRequest requestWithBucket:[self bucket] key:[self key]];
|
||||
}
|
||||
|
||||
- (ASIS3ObjectRequest *)PUTRequestWithFile:(NSString *)filePath
|
||||
{
|
||||
return [ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:[self bucket] key:[self key]];
|
||||
}
|
||||
|
||||
- (ASIS3ObjectRequest *)DELETERequest
|
||||
{
|
||||
ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:[self bucket] key:[self key]];
|
||||
[request setRequestMethod:@"DELETE"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"Key: %@ lastModified: %@ ETag: %@ size: %llu ownerID: %@ ownerName: %@",[self key],[self lastModified],[self ETag],[self size],[self ownerID],[self ownerName]];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIS3BucketObject *newBucketObject = [[[self class] alloc] init];
|
||||
[newBucketObject setBucket:[self bucket]];
|
||||
[newBucketObject setKey:[self key]];
|
||||
[newBucketObject setLastModified:[self lastModified]];
|
||||
[newBucketObject setETag:[self ETag]];
|
||||
[newBucketObject setSize:[self size]];
|
||||
[newBucketObject setOwnerID:[self ownerID]];
|
||||
[newBucketObject setOwnerName:[self ownerName]];
|
||||
return newBucketObject;
|
||||
}
|
||||
|
||||
@synthesize bucket;
|
||||
@synthesize key;
|
||||
@synthesize lastModified;
|
||||
@synthesize ETag;
|
||||
@synthesize size;
|
||||
@synthesize ownerID;
|
||||
@synthesize ownerName;
|
||||
@end
|
72
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketRequest.h
generated
Normal file
72
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketRequest.h
generated
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// ASIS3BucketRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// Use this class to create buckets, fetch a list of their contents, and delete buckets
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIS3Request.h"
|
||||
|
||||
@class ASIS3BucketObject;
|
||||
|
||||
@interface ASIS3BucketRequest : ASIS3Request {
|
||||
|
||||
// Name of the bucket to talk to
|
||||
NSString *bucket;
|
||||
|
||||
// A parameter passed to S3 in the query string to tell it to return specialised information
|
||||
// Consult the S3 REST API documentation for more info
|
||||
NSString *subResource;
|
||||
|
||||
// Options for filtering GET requests
|
||||
// See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html
|
||||
NSString *prefix;
|
||||
NSString *marker;
|
||||
int maxResultCount;
|
||||
NSString *delimiter;
|
||||
|
||||
// Internally used while parsing the response
|
||||
ASIS3BucketObject *currentObject;
|
||||
|
||||
// Returns an array of ASIS3BucketObjects created from the XML response
|
||||
NSMutableArray *objects;
|
||||
|
||||
// Will be populated with a list of 'folders' when a delimiter is set
|
||||
NSMutableArray *commonPrefixes;
|
||||
|
||||
// Will be true if this request did not return all the results matching the query (use maxResultCount to configure the number of results to return)
|
||||
BOOL isTruncated;
|
||||
}
|
||||
|
||||
// Fetch a bucket
|
||||
+ (id)requestWithBucket:(NSString *)bucket;
|
||||
|
||||
// Create a bucket request, passing a parameter in the query string
|
||||
// You'll need to parse the response XML yourself
|
||||
// Examples:
|
||||
// Fetch ACL:
|
||||
// ASIS3BucketRequest *request = [ASIS3BucketRequest requestWithBucket:@"mybucket" parameter:@"acl"];
|
||||
// Fetch Location:
|
||||
// ASIS3BucketRequest *request = [ASIS3BucketRequest requestWithBucket:@"mybucket" parameter:@"location"];
|
||||
// See the S3 REST API docs for more information about the parameters you can pass
|
||||
+ (id)requestWithBucket:(NSString *)bucket subResource:(NSString *)subResource;
|
||||
|
||||
// Use for creating new buckets
|
||||
+ (id)PUTRequestWithBucket:(NSString *)bucket;
|
||||
|
||||
// Use for deleting buckets - they must be empty for this to succeed
|
||||
+ (id)DELETERequestWithBucket:(NSString *)bucket;
|
||||
|
||||
@property (retain, nonatomic) NSString *bucket;
|
||||
@property (retain, nonatomic) NSString *subResource;
|
||||
@property (retain, nonatomic) NSString *prefix;
|
||||
@property (retain, nonatomic) NSString *marker;
|
||||
@property (assign, nonatomic) int maxResultCount;
|
||||
@property (retain, nonatomic) NSString *delimiter;
|
||||
@property (retain, readonly) NSMutableArray *objects;
|
||||
@property (retain, readonly) NSMutableArray *commonPrefixes;
|
||||
@property (assign, readonly) BOOL isTruncated;
|
||||
@end
|
175
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketRequest.m
generated
Normal file
175
Pods/ASIHTTPRequest/Classes/S3/ASIS3BucketRequest.m
generated
Normal file
|
@ -0,0 +1,175 @@
|
|||
//
|
||||
// ASIS3BucketRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3BucketRequest.h"
|
||||
#import "ASIS3BucketObject.h"
|
||||
|
||||
|
||||
// Private stuff
|
||||
@interface ASIS3BucketRequest ()
|
||||
@property (retain, nonatomic) ASIS3BucketObject *currentObject;
|
||||
@property (retain) NSMutableArray *objects;
|
||||
@property (retain) NSMutableArray *commonPrefixes;
|
||||
@property (assign) BOOL isTruncated;
|
||||
@end
|
||||
|
||||
@implementation ASIS3BucketRequest
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setObjects:[[[NSMutableArray alloc] init] autorelease]];
|
||||
[self setCommonPrefixes:[[[NSMutableArray alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)requestWithBucket:(NSString *)theBucket
|
||||
{
|
||||
ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease];
|
||||
[request setBucket:theBucket];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)requestWithBucket:(NSString *)theBucket subResource:(NSString *)theSubResource
|
||||
{
|
||||
ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease];
|
||||
[request setBucket:theBucket];
|
||||
[request setSubResource:theSubResource];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)PUTRequestWithBucket:(NSString *)theBucket
|
||||
{
|
||||
ASIS3BucketRequest *request = [self requestWithBucket:theBucket];
|
||||
[request setRequestMethod:@"PUT"];
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
+ (id)DELETERequestWithBucket:(NSString *)theBucket
|
||||
{
|
||||
ASIS3BucketRequest *request = [self requestWithBucket:theBucket];
|
||||
[request setRequestMethod:@"DELETE"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[currentObject release];
|
||||
[objects release];
|
||||
[commonPrefixes release];
|
||||
[prefix release];
|
||||
[marker release];
|
||||
[delimiter release];
|
||||
[subResource release];
|
||||
[bucket release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)canonicalizedResource
|
||||
{
|
||||
if ([self subResource]) {
|
||||
return [NSString stringWithFormat:@"/%@/?%@",[self bucket],[self subResource]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"/%@/",[self bucket]];
|
||||
}
|
||||
|
||||
- (void)buildURL
|
||||
{
|
||||
NSString *baseURL;
|
||||
if ([self subResource]) {
|
||||
baseURL = [NSString stringWithFormat:@"%@://%@.%@/?%@",[self requestScheme],[self bucket],[[self class] S3Host],[self subResource]];
|
||||
} else {
|
||||
baseURL = [NSString stringWithFormat:@"%@://%@.%@",[self requestScheme],[self bucket],[[self class] S3Host]];
|
||||
}
|
||||
NSMutableArray *queryParts = [[[NSMutableArray alloc] init] autorelease];
|
||||
if ([self prefix]) {
|
||||
[queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
if ([self marker]) {
|
||||
[queryParts addObject:[NSString stringWithFormat:@"marker=%@",[[self marker] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
if ([self delimiter]) {
|
||||
[queryParts addObject:[NSString stringWithFormat:@"delimiter=%@",[[self delimiter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
if ([self maxResultCount] > 0) {
|
||||
[queryParts addObject:[NSString stringWithFormat:@"max-keys=%hi",[self maxResultCount]]];
|
||||
}
|
||||
if ([queryParts count]) {
|
||||
NSString* template = @"%@?%@";
|
||||
if ([[self subResource] length] > 0) {
|
||||
template = @"%@&%@";
|
||||
}
|
||||
[self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,baseURL,[queryParts componentsJoinedByString:@"&"]]]];
|
||||
} else {
|
||||
[self setURL:[NSURL URLWithString:baseURL]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
|
||||
{
|
||||
if ([elementName isEqualToString:@"Contents"]) {
|
||||
[self setCurrentObject:[ASIS3BucketObject objectWithBucket:[self bucket]]];
|
||||
}
|
||||
[super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
|
||||
{
|
||||
if ([elementName isEqualToString:@"Contents"]) {
|
||||
[objects addObject:currentObject];
|
||||
[self setCurrentObject:nil];
|
||||
} else if ([elementName isEqualToString:@"Key"]) {
|
||||
[[self currentObject] setKey:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"LastModified"]) {
|
||||
[[self currentObject] setLastModified:[[ASIS3Request S3ResponseDateFormatter] dateFromString:[self currentXMLElementContent]]];
|
||||
} else if ([elementName isEqualToString:@"ETag"]) {
|
||||
[[self currentObject] setETag:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"Size"]) {
|
||||
[[self currentObject] setSize:(unsigned long long)[[self currentXMLElementContent] longLongValue]];
|
||||
} else if ([elementName isEqualToString:@"ID"]) {
|
||||
[[self currentObject] setOwnerID:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"DisplayName"]) {
|
||||
[[self currentObject] setOwnerName:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"Prefix"] && [[self currentXMLElementStack] count] > 2 && [[[self currentXMLElementStack] objectAtIndex:[[self currentXMLElementStack] count]-2] isEqualToString:@"CommonPrefixes"]) {
|
||||
[[self commonPrefixes] addObject:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"IsTruncated"]) {
|
||||
[self setIsTruncated:[[self currentXMLElementContent] isEqualToString:@"true"]];
|
||||
} else {
|
||||
// Let ASIS3Request look for error messages
|
||||
[super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIS3BucketRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setBucket:[self bucket]];
|
||||
[newRequest setSubResource:[self subResource]];
|
||||
[newRequest setPrefix:[self prefix]];
|
||||
[newRequest setMarker:[self marker]];
|
||||
[newRequest setMaxResultCount:[self maxResultCount]];
|
||||
[newRequest setDelimiter:[self delimiter]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
@synthesize bucket;
|
||||
@synthesize subResource;
|
||||
@synthesize currentObject;
|
||||
@synthesize objects;
|
||||
@synthesize commonPrefixes;
|
||||
@synthesize prefix;
|
||||
@synthesize marker;
|
||||
@synthesize maxResultCount;
|
||||
@synthesize delimiter;
|
||||
@synthesize isTruncated;
|
||||
|
||||
@end
|
80
Pods/ASIHTTPRequest/Classes/S3/ASIS3ObjectRequest.h
generated
Normal file
80
Pods/ASIHTTPRequest/Classes/S3/ASIS3ObjectRequest.h
generated
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ASIS3ObjectRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// Use an ASIS3ObjectRequest to fetch, upload, copy and delete objects on Amazon S3
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIS3Request.h"
|
||||
|
||||
// Constants for storage class
|
||||
extern NSString *const ASIS3StorageClassStandard;
|
||||
extern NSString *const ASIS3StorageClassReducedRedundancy;
|
||||
|
||||
@interface ASIS3ObjectRequest : ASIS3Request {
|
||||
|
||||
// Name of the bucket to talk to
|
||||
NSString *bucket;
|
||||
|
||||
// Key of the resource you want to access on S3
|
||||
NSString *key;
|
||||
|
||||
// The bucket + path of the object to be copied (used with COPYRequestFromBucket:path:toBucket:path:)
|
||||
NSString *sourceBucket;
|
||||
NSString *sourceKey;
|
||||
|
||||
// The mime type of the content for PUT requests
|
||||
// Set this if having the correct mime type returned to you when you GET the data is important (eg it will be served by a web-server)
|
||||
// Can be autodetected when PUTing a file from disk, will default to 'application/octet-stream' when PUTing data
|
||||
NSString *mimeType;
|
||||
|
||||
// Set this to specify you want to work with a particular subresource (eg an acl for that resource)
|
||||
// See requestWithBucket:key:subResource:, below.
|
||||
NSString* subResource;
|
||||
|
||||
// The storage class to be used for PUT requests
|
||||
// Set this to ASIS3StorageClassReducedRedundancy to save money on storage, at (presumably) a slightly higher risk you will lose the data
|
||||
// If this is not set, no x-amz-storage-class header will be sent to S3, and their default will be used
|
||||
NSString *storageClass;
|
||||
}
|
||||
|
||||
// Create a request, building an appropriate url
|
||||
+ (id)requestWithBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
// Create a request for an object, passing a parameter in the query string
|
||||
// You'll need to parse the response XML yourself
|
||||
// Examples:
|
||||
// Fetch ACL:
|
||||
// ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:@"mybucket" key:@"my-key" parameter:@"acl"];
|
||||
// Get object torret:
|
||||
// ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:@"mybucket" key:@"my-key" parameter:@"torrent"];
|
||||
// See the S3 REST API docs for more information about the parameters you can pass
|
||||
+ (id)requestWithBucket:(NSString *)bucket key:(NSString *)key subResource:(NSString *)subResource;
|
||||
|
||||
// Create a PUT request using the file at filePath as the body
|
||||
+ (id)PUTRequestForFile:(NSString *)filePath withBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
// Create a PUT request using the supplied NSData as the body (set the mime-type manually with setMimeType: if necessary)
|
||||
+ (id)PUTRequestForData:(NSData *)data withBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
// Create a DELETE request for the object at path
|
||||
+ (id)DELETERequestWithBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
// Create a PUT request to copy an object from one location to another
|
||||
// Clang will complain because it thinks this method should return an object with +1 retain :(
|
||||
+ (id)COPYRequestFromBucket:(NSString *)sourceBucket key:(NSString *)sourceKey toBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
// Creates a HEAD request for the object at path
|
||||
+ (id)HEADRequestWithBucket:(NSString *)bucket key:(NSString *)key;
|
||||
|
||||
@property (retain, nonatomic) NSString *bucket;
|
||||
@property (retain, nonatomic) NSString *key;
|
||||
@property (retain, nonatomic) NSString *sourceBucket;
|
||||
@property (retain, nonatomic) NSString *sourceKey;
|
||||
@property (retain, nonatomic) NSString *mimeType;
|
||||
@property (retain, nonatomic) NSString *subResource;
|
||||
@property (retain, nonatomic) NSString *storageClass;
|
||||
@end
|
162
Pods/ASIHTTPRequest/Classes/S3/ASIS3ObjectRequest.m
generated
Normal file
162
Pods/ASIHTTPRequest/Classes/S3/ASIS3ObjectRequest.m
generated
Normal file
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// ASIS3ObjectRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3ObjectRequest.h"
|
||||
|
||||
NSString *const ASIS3StorageClassStandard = @"STANDARD";
|
||||
NSString *const ASIS3StorageClassReducedRedundancy = @"REDUCED_REDUNDANCY";
|
||||
|
||||
@implementation ASIS3ObjectRequest
|
||||
|
||||
- (ASIHTTPRequest *)HEADRequest
|
||||
{
|
||||
ASIS3ObjectRequest *headRequest = (ASIS3ObjectRequest *)[super HEADRequest];
|
||||
[headRequest setKey:[self key]];
|
||||
[headRequest setBucket:[self bucket]];
|
||||
return headRequest;
|
||||
}
|
||||
|
||||
+ (id)requestWithBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [[[self alloc] initWithURL:nil] autorelease];
|
||||
[newRequest setBucket:theBucket];
|
||||
[newRequest setKey:theKey];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)requestWithBucket:(NSString *)theBucket key:(NSString *)theKey subResource:(NSString *)theSubResource
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [[[self alloc] initWithURL:nil] autorelease];
|
||||
[newRequest setSubResource:theSubResource];
|
||||
[newRequest setBucket:theBucket];
|
||||
[newRequest setKey:theKey];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)PUTRequestForData:(NSData *)data withBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey];
|
||||
[newRequest appendPostData:data];
|
||||
[newRequest setRequestMethod:@"PUT"];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)PUTRequestForFile:(NSString *)filePath withBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey];
|
||||
[newRequest setPostBodyFilePath:filePath];
|
||||
[newRequest setShouldStreamPostDataFromDisk:YES];
|
||||
[newRequest setRequestMethod:@"PUT"];
|
||||
[newRequest setMimeType:[ASIHTTPRequest mimeTypeForFileAtPath:filePath]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)DELETERequestWithBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey];
|
||||
[newRequest setRequestMethod:@"DELETE"];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)COPYRequestFromBucket:(NSString *)theSourceBucket key:(NSString *)theSourceKey toBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey];
|
||||
[newRequest setRequestMethod:@"PUT"];
|
||||
[newRequest setSourceBucket:theSourceBucket];
|
||||
[newRequest setSourceKey:theSourceKey];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
+ (id)HEADRequestWithBucket:(NSString *)theBucket key:(NSString *)theKey
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey];
|
||||
[newRequest setRequestMethod:@"HEAD"];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIS3ObjectRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setBucket:[self bucket]];
|
||||
[newRequest setKey:[self key]];
|
||||
[newRequest setMimeType:[self mimeType]];
|
||||
[newRequest setSourceBucket:[self sourceBucket]];
|
||||
[newRequest setSourceKey:[self sourceKey]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[bucket release];
|
||||
[key release];
|
||||
[mimeType release];
|
||||
[sourceKey release];
|
||||
[sourceBucket release];
|
||||
[subResource release];
|
||||
[storageClass release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)buildURL
|
||||
{
|
||||
if ([self subResource]) {
|
||||
[self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@?%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]],[self subResource]]]];
|
||||
} else {
|
||||
[self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]]];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)mimeType
|
||||
{
|
||||
if (mimeType) {
|
||||
return mimeType;
|
||||
} else if ([self postBodyFilePath]) {
|
||||
return [ASIHTTPRequest mimeTypeForFileAtPath:[self postBodyFilePath]];
|
||||
} else {
|
||||
return @"application/octet-stream";
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)canonicalizedResource
|
||||
{
|
||||
if ([[self subResource] length] > 0) {
|
||||
return [NSString stringWithFormat:@"/%@%@?%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]], [self subResource]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"/%@%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]]];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)S3Headers
|
||||
{
|
||||
NSMutableDictionary *headers = [super S3Headers];
|
||||
if ([self sourceKey]) {
|
||||
NSString *path = [ASIS3Request stringByURLEncodingForS3Path:[self sourceKey]];
|
||||
[headers setObject:[[self sourceBucket] stringByAppendingString:path] forKey:@"x-amz-copy-source"];
|
||||
}
|
||||
if ([self storageClass]) {
|
||||
[headers setObject:[self storageClass] forKey:@"x-amz-storage-class"];
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
- (NSString *)stringToSignForHeaders:(NSString *)canonicalizedAmzHeaders resource:(NSString *)canonicalizedResource
|
||||
{
|
||||
if ([[self requestMethod] isEqualToString:@"PUT"] && ![self sourceKey]) {
|
||||
[self addRequestHeader:@"Content-Type" value:[self mimeType]];
|
||||
return [NSString stringWithFormat:@"PUT\n\n%@\n%@\n%@%@",[self mimeType],dateString,canonicalizedAmzHeaders,canonicalizedResource];
|
||||
}
|
||||
return [super stringToSignForHeaders:canonicalizedAmzHeaders resource:canonicalizedResource];
|
||||
}
|
||||
|
||||
@synthesize bucket;
|
||||
@synthesize key;
|
||||
@synthesize sourceBucket;
|
||||
@synthesize sourceKey;
|
||||
@synthesize mimeType;
|
||||
@synthesize subResource;
|
||||
@synthesize storageClass;
|
||||
@end
|
109
Pods/ASIHTTPRequest/Classes/S3/ASIS3Request.h
generated
Normal file
109
Pods/ASIHTTPRequest/Classes/S3/ASIS3Request.h
generated
Normal file
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// ASIS3Request.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 30/06/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A class for accessing data stored on Amazon's Simple Storage Service (http://aws.amazon.com/s3/) using the REST API
|
||||
// While you can use this class directly, the included subclasses make typical operations easier
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
|
||||
#import "ASINSXMLParserCompat.h"
|
||||
#endif
|
||||
|
||||
// See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAccessPolicy.html for what these mean
|
||||
extern NSString *const ASIS3AccessPolicyPrivate; // This is the default in S3 when no access policy header is provided
|
||||
extern NSString *const ASIS3AccessPolicyPublicRead;
|
||||
extern NSString *const ASIS3AccessPolicyPublicReadWrite;
|
||||
extern NSString *const ASIS3AccessPolicyAuthenticatedRead;
|
||||
extern NSString *const ASIS3AccessPolicyBucketOwnerRead;
|
||||
extern NSString *const ASIS3AccessPolicyBucketOwnerFullControl;
|
||||
|
||||
// Constants for requestScheme - defaults is ASIS3RequestSchemeHTTP
|
||||
extern NSString *const ASIS3RequestSchemeHTTP;
|
||||
extern NSString *const ASIS3RequestSchemeHTTPS;
|
||||
|
||||
|
||||
|
||||
typedef enum _ASIS3ErrorType {
|
||||
ASIS3ResponseParsingFailedType = 1,
|
||||
ASIS3ResponseErrorType = 2
|
||||
} ASIS3ErrorType;
|
||||
|
||||
|
||||
|
||||
@interface ASIS3Request : ASIHTTPRequest <NSCopying, NSXMLParserDelegate> {
|
||||
|
||||
// Your S3 access key. Set it on the request, or set it globally using [ASIS3Request setSharedAccessKey:]
|
||||
NSString *accessKey;
|
||||
|
||||
// Your S3 secret access key. Set it on the request, or set it globally using [ASIS3Request setSharedSecretAccessKey:]
|
||||
NSString *secretAccessKey;
|
||||
|
||||
// Set to ASIS3RequestSchemeHTTPS to send your requests via HTTPS (default is ASIS3RequestSchemeHTTP)
|
||||
NSString *requestScheme;
|
||||
|
||||
// The string that will be used in the HTTP date header. Generally you'll want to ignore this and let the class add the current date for you, but the accessor is used by the tests
|
||||
NSString *dateString;
|
||||
|
||||
// The access policy to use when PUTting a file (see the string constants at the top ASIS3Request.h for details on what the possible options are)
|
||||
NSString *accessPolicy;
|
||||
|
||||
// Internally used while parsing errors
|
||||
NSString *currentXMLElementContent;
|
||||
NSMutableArray *currentXMLElementStack;
|
||||
}
|
||||
|
||||
// Uses the supplied date to create a Date header string
|
||||
- (void)setDate:(NSDate *)date;
|
||||
|
||||
// Will return a dictionary of the 'amz-' headers that wil be sent to S3
|
||||
// Override in subclasses to add new ones
|
||||
- (NSMutableDictionary *)S3Headers;
|
||||
|
||||
// Returns the string that will used to create a signature for this request
|
||||
// Is overridden in ASIS3ObjectRequest
|
||||
- (NSString *)stringToSignForHeaders:(NSString *)canonicalizedAmzHeaders resource:(NSString *)canonicalizedResource;
|
||||
|
||||
// Parses the response to work out if S3 returned an error
|
||||
- (void)parseResponseXML;
|
||||
|
||||
#pragma mark shared access keys
|
||||
|
||||
// Get and set the global access key, this will be used for all requests the access key hasn't been set for
|
||||
+ (NSString *)sharedAccessKey;
|
||||
+ (void)setSharedAccessKey:(NSString *)newAccessKey;
|
||||
+ (NSString *)sharedSecretAccessKey;
|
||||
+ (void)setSharedSecretAccessKey:(NSString *)newAccessKey;
|
||||
|
||||
# pragma mark helpers
|
||||
|
||||
// Returns a date formatter than can be used to parse a date from S3
|
||||
+ (NSDateFormatter*)S3ResponseDateFormatter;
|
||||
|
||||
// Returns a date formatter than can be used to send a date header to S3
|
||||
+ (NSDateFormatter*)S3RequestDateFormatter;
|
||||
|
||||
|
||||
// URL-encodes an S3 key so it can be used in a url
|
||||
// You shouldn't normally need to use this yourself
|
||||
+ (NSString *)stringByURLEncodingForS3Path:(NSString *)key;
|
||||
|
||||
// Returns a string for the hostname used for S3 requests. You shouldn't ever need to change this.
|
||||
+ (NSString *)S3Host;
|
||||
|
||||
// This is called automatically before the request starts to build the request URL (if one has not been manually set already)
|
||||
- (void)buildURL;
|
||||
|
||||
@property (retain) NSString *dateString;
|
||||
@property (retain) NSString *accessKey;
|
||||
@property (retain) NSString *secretAccessKey;
|
||||
@property (retain) NSString *accessPolicy;
|
||||
@property (retain) NSString *currentXMLElementContent;
|
||||
@property (retain) NSMutableArray *currentXMLElementStack;
|
||||
@property (retain) NSString *requestScheme;
|
||||
@end
|
311
Pods/ASIHTTPRequest/Classes/S3/ASIS3Request.m
generated
Normal file
311
Pods/ASIHTTPRequest/Classes/S3/ASIS3Request.m
generated
Normal file
|
@ -0,0 +1,311 @@
|
|||
//
|
||||
// ASIS3Request.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 30/06/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3Request.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
NSString *const ASIS3AccessPolicyPrivate = @"private";
|
||||
NSString *const ASIS3AccessPolicyPublicRead = @"public-read";
|
||||
NSString *const ASIS3AccessPolicyPublicReadWrite = @"public-read-write";
|
||||
NSString *const ASIS3AccessPolicyAuthenticatedRead = @"authenticated-read";
|
||||
NSString *const ASIS3AccessPolicyBucketOwnerRead = @"bucket-owner-read";
|
||||
NSString *const ASIS3AccessPolicyBucketOwnerFullControl = @"bucket-owner-full-control";
|
||||
|
||||
NSString *const ASIS3RequestSchemeHTTP = @"http";
|
||||
NSString *const ASIS3RequestSchemeHTTPS = @"https";
|
||||
|
||||
static NSString *sharedAccessKey = nil;
|
||||
static NSString *sharedSecretAccessKey = nil;
|
||||
|
||||
// Private stuff
|
||||
@interface ASIS3Request ()
|
||||
+ (NSData *)HMACSHA1withKey:(NSString *)key forString:(NSString *)string;
|
||||
@end
|
||||
|
||||
@implementation ASIS3Request
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
// After a bit of experimentation/guesswork, this number seems to reduce the chance of a 'RequestTimeout' error
|
||||
[self setPersistentConnectionTimeoutSeconds:20];
|
||||
[self setRequestScheme:ASIS3RequestSchemeHTTP];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[currentXMLElementContent release];
|
||||
[currentXMLElementStack release];
|
||||
[dateString release];
|
||||
[accessKey release];
|
||||
[secretAccessKey release];
|
||||
[accessPolicy release];
|
||||
[requestScheme release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
- (void)setDate:(NSDate *)date
|
||||
{
|
||||
[self setDateString:[[ASIS3Request S3RequestDateFormatter] stringFromDate:date]];
|
||||
}
|
||||
|
||||
- (ASIHTTPRequest *)HEADRequest
|
||||
{
|
||||
ASIS3Request *headRequest = (ASIS3Request *)[super HEADRequest];
|
||||
[headRequest setAccessKey:[self accessKey]];
|
||||
[headRequest setSecretAccessKey:[self secretAccessKey]];
|
||||
return headRequest;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)S3Headers
|
||||
{
|
||||
NSMutableDictionary *headers = [NSMutableDictionary dictionary];
|
||||
if ([self accessPolicy]) {
|
||||
[headers setObject:[self accessPolicy] forKey:@"x-amz-acl"];
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
- (void)main
|
||||
{
|
||||
if (![self url]) {
|
||||
[self buildURL];
|
||||
}
|
||||
[super main];
|
||||
}
|
||||
|
||||
- (NSString *)canonicalizedResource
|
||||
{
|
||||
return @"/";
|
||||
}
|
||||
|
||||
- (NSString *)stringToSignForHeaders:(NSString *)canonicalizedAmzHeaders resource:(NSString *)canonicalizedResource
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@\n\n\n%@\n%@%@",[self requestMethod],[self dateString],canonicalizedAmzHeaders,canonicalizedResource];
|
||||
}
|
||||
|
||||
- (void)buildRequestHeaders
|
||||
{
|
||||
if (![self url]) {
|
||||
[self buildURL];
|
||||
}
|
||||
[super buildRequestHeaders];
|
||||
|
||||
// If an access key / secret access key haven't been set for this request, let's use the shared keys
|
||||
if (![self accessKey]) {
|
||||
[self setAccessKey:[ASIS3Request sharedAccessKey]];
|
||||
}
|
||||
if (![self secretAccessKey]) {
|
||||
[self setSecretAccessKey:[ASIS3Request sharedSecretAccessKey]];
|
||||
}
|
||||
// If a date string hasn't been set, we'll create one from the current time
|
||||
if (![self dateString]) {
|
||||
[self setDate:[NSDate date]];
|
||||
}
|
||||
[self addRequestHeader:@"Date" value:[self dateString]];
|
||||
|
||||
// Ensure our formatted string doesn't use '(null)' for the empty path
|
||||
NSString *canonicalizedResource = [self canonicalizedResource];
|
||||
|
||||
// Add a header for the access policy if one was set, otherwise we won't add one (and S3 will default to private)
|
||||
NSMutableDictionary *amzHeaders = [self S3Headers];
|
||||
NSString *canonicalizedAmzHeaders = @"";
|
||||
for (NSString *header in [amzHeaders keysSortedByValueUsingSelector:@selector(compare:)]) {
|
||||
canonicalizedAmzHeaders = [NSString stringWithFormat:@"%@%@:%@\n",canonicalizedAmzHeaders,[header lowercaseString],[amzHeaders objectForKey:header]];
|
||||
[self addRequestHeader:header value:[amzHeaders objectForKey:header]];
|
||||
}
|
||||
|
||||
// Jump through hoops while eating hot food
|
||||
NSString *stringToSign = [self stringToSignForHeaders:canonicalizedAmzHeaders resource:canonicalizedResource];
|
||||
NSString *signature = [ASIHTTPRequest base64forData:[ASIS3Request HMACSHA1withKey:[self secretAccessKey] forString:stringToSign]];
|
||||
NSString *authorizationString = [NSString stringWithFormat:@"AWS %@:%@",[self accessKey],signature];
|
||||
[self addRequestHeader:@"Authorization" value:authorizationString];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)requestFinished
|
||||
{
|
||||
if ([[[self responseHeaders] objectForKey:@"Content-Type"] isEqualToString:@"application/xml"]) {
|
||||
[self parseResponseXML];
|
||||
}
|
||||
if (![self error]) {
|
||||
[super requestFinished];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Error XML parsing
|
||||
|
||||
- (void)parseResponseXML
|
||||
{
|
||||
NSData* xmlData = [self responseData];
|
||||
if (![xmlData length]) {
|
||||
return;
|
||||
}
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:xmlData] autorelease];
|
||||
[self setCurrentXMLElementStack:[NSMutableArray array]];
|
||||
[parser setDelegate:self];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
|
||||
{
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIS3ResponseParsingFailedType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Parsing the resposnse failed",NSLocalizedDescriptionKey,parseError,NSUnderlyingErrorKey,nil]]];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
|
||||
{
|
||||
[self setCurrentXMLElementContent:@""];
|
||||
[[self currentXMLElementStack] addObject:elementName];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
|
||||
{
|
||||
[[self currentXMLElementStack] removeLastObject];
|
||||
if ([elementName isEqualToString:@"Message"]) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIS3ResponseErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[self currentXMLElementContent],NSLocalizedDescriptionKey,nil]]];
|
||||
// Handle S3 connection expiry errors
|
||||
} else if ([elementName isEqualToString:@"Code"]) {
|
||||
if ([[self currentXMLElementContent] isEqualToString:@"RequestTimeout"]) {
|
||||
if ([self retryUsingNewConnection]) {
|
||||
[parser abortParsing];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
|
||||
{
|
||||
[self setCurrentXMLElementContent:[[self currentXMLElementContent] stringByAppendingString:string]];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIS3Request *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setAccessKey:[self accessKey]];
|
||||
[newRequest setSecretAccessKey:[self secretAccessKey]];
|
||||
[newRequest setAccessPolicy:[self accessPolicy]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Shared access keys
|
||||
|
||||
+ (NSString *)sharedAccessKey
|
||||
{
|
||||
return sharedAccessKey;
|
||||
}
|
||||
|
||||
+ (void)setSharedAccessKey:(NSString *)newAccessKey
|
||||
{
|
||||
[sharedAccessKey release];
|
||||
sharedAccessKey = [newAccessKey retain];
|
||||
}
|
||||
|
||||
+ (NSString *)sharedSecretAccessKey
|
||||
{
|
||||
return sharedSecretAccessKey;
|
||||
}
|
||||
|
||||
+ (void)setSharedSecretAccessKey:(NSString *)newAccessKey
|
||||
{
|
||||
[sharedSecretAccessKey release];
|
||||
sharedSecretAccessKey = [newAccessKey retain];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark helpers
|
||||
|
||||
+ (NSString *)stringByURLEncodingForS3Path:(NSString *)key
|
||||
{
|
||||
if (!key) {
|
||||
return @"/";
|
||||
}
|
||||
NSString *path = [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)key, NULL, CFSTR(":?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) autorelease];
|
||||
if (![[path substringWithRange:NSMakeRange(0, 1)] isEqualToString:@"/"]) {
|
||||
path = [@"/" stringByAppendingString:path];
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// Thanks to Tom Andersen for pointing out the threading issues and providing this code!
|
||||
+ (NSDateFormatter*)S3ResponseDateFormatter
|
||||
{
|
||||
// We store our date formatter in the calling thread's dictionary
|
||||
// NSDateFormatter is not thread-safe, this approach ensures each formatter is only used on a single thread
|
||||
// This formatter can be reused 1000 times in parsing a single response, so it would be expensive to keep creating new date formatters
|
||||
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
|
||||
NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASIS3ResponseDateFormatter"];
|
||||
if (dateFormatter == nil) {
|
||||
dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
|
||||
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
|
||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'.000Z'"];
|
||||
[threadDict setObject:dateFormatter forKey:@"ASIS3ResponseDateFormatter"];
|
||||
}
|
||||
return dateFormatter;
|
||||
}
|
||||
|
||||
+ (NSDateFormatter*)S3RequestDateFormatter
|
||||
{
|
||||
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
|
||||
NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASIS3RequestHeaderDateFormatter"];
|
||||
if (dateFormatter == nil) {
|
||||
dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||
// Prevent problems with dates generated by other locales (tip from: http://rel.me/t/date/)
|
||||
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
|
||||
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
|
||||
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss Z"];
|
||||
[threadDict setObject:dateFormatter forKey:@"ASIS3RequestHeaderDateFormatter"];
|
||||
}
|
||||
return dateFormatter;
|
||||
|
||||
}
|
||||
|
||||
// From: http://stackoverflow.com/questions/476455/is-there-a-library-for-iphone-to-work-with-hmac-sha-1-encoding
|
||||
|
||||
+ (NSData *)HMACSHA1withKey:(NSString *)key forString:(NSString *)string
|
||||
{
|
||||
NSData *clearTextData = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
|
||||
|
||||
CCHmacContext hmacContext;
|
||||
CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length);
|
||||
CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length);
|
||||
CCHmacFinal(&hmacContext, digest);
|
||||
|
||||
return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
+ (NSString *)S3Host
|
||||
{
|
||||
return @"s3.amazonaws.com";
|
||||
}
|
||||
|
||||
- (void)buildURL
|
||||
{
|
||||
}
|
||||
|
||||
@synthesize dateString;
|
||||
@synthesize accessKey;
|
||||
@synthesize secretAccessKey;
|
||||
@synthesize currentXMLElementContent;
|
||||
@synthesize currentXMLElementStack;
|
||||
@synthesize accessPolicy;
|
||||
@synthesize requestScheme;
|
||||
@end
|
31
Pods/ASIHTTPRequest/Classes/S3/ASIS3ServiceRequest.h
generated
Normal file
31
Pods/ASIHTTPRequest/Classes/S3/ASIS3ServiceRequest.h
generated
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ASIS3ServiceRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// Create an ASIS3ServiceRequest to obtain a list of your buckets
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIS3Request.h"
|
||||
|
||||
@class ASIS3Bucket;
|
||||
|
||||
@interface ASIS3ServiceRequest : ASIS3Request {
|
||||
|
||||
// Internally used while parsing the response
|
||||
ASIS3Bucket *currentBucket;
|
||||
NSString *ownerName;
|
||||
NSString *ownerID;
|
||||
|
||||
// A list of the buckets stored on S3 for this account
|
||||
NSMutableArray *buckets;
|
||||
}
|
||||
|
||||
// Perform a GET request on the S3 service
|
||||
// This will fetch a list of the buckets attached to the S3 account
|
||||
+ (id)serviceRequest;
|
||||
|
||||
@property (retain, readonly) NSMutableArray *buckets;
|
||||
@end
|
80
Pods/ASIHTTPRequest/Classes/S3/ASIS3ServiceRequest.m
generated
Normal file
80
Pods/ASIHTTPRequest/Classes/S3/ASIS3ServiceRequest.m
generated
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ASIS3ServiceRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 16/03/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIS3ServiceRequest.h"
|
||||
#import "ASIS3Bucket.h"
|
||||
|
||||
// Private stuff
|
||||
@interface ASIS3ServiceRequest ()
|
||||
@property (retain) NSMutableArray *buckets;
|
||||
@property (retain, nonatomic) ASIS3Bucket *currentBucket;
|
||||
@property (retain, nonatomic) NSString *ownerID;
|
||||
@property (retain, nonatomic) NSString *ownerName;
|
||||
@end
|
||||
|
||||
@implementation ASIS3ServiceRequest
|
||||
|
||||
+ (id)serviceRequest
|
||||
{
|
||||
ASIS3ServiceRequest *request = [[[self alloc] initWithURL:nil] autorelease];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setBuckets:[[[NSMutableArray alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[buckets release];
|
||||
[currentBucket release];
|
||||
[ownerID release];
|
||||
[ownerName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)buildURL
|
||||
{
|
||||
[self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@",[self requestScheme],[[self class] S3Host]]]];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
|
||||
{
|
||||
if ([elementName isEqualToString:@"Bucket"]) {
|
||||
[self setCurrentBucket:[ASIS3Bucket bucketWithOwnerID:[self ownerID] ownerName:[self ownerName]]];
|
||||
}
|
||||
[super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
|
||||
{
|
||||
if ([elementName isEqualToString:@"Bucket"]) {
|
||||
[[self buckets] addObject:[self currentBucket]];
|
||||
[self setCurrentBucket:nil];
|
||||
} else if ([elementName isEqualToString:@"Name"]) {
|
||||
[[self currentBucket] setName:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"CreationDate"]) {
|
||||
[[self currentBucket] setCreationDate:[[ASIS3Request S3ResponseDateFormatter] dateFromString:[self currentXMLElementContent]]];
|
||||
} else if ([elementName isEqualToString:@"ID"]) {
|
||||
[self setOwnerID:[self currentXMLElementContent]];
|
||||
} else if ([elementName isEqualToString:@"DisplayName"]) {
|
||||
[self setOwnerName:[self currentXMLElementContent]];
|
||||
} else {
|
||||
// Let ASIS3Request look for error messages
|
||||
[super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName];
|
||||
}
|
||||
}
|
||||
|
||||
@synthesize buckets;
|
||||
@synthesize currentBucket;
|
||||
@synthesize ownerID;
|
||||
@synthesize ownerName;
|
||||
@end
|
28
Pods/ASIHTTPRequest/LICENSE
generated
Normal file
28
Pods/ASIHTTPRequest/LICENSE
generated
Normal file
|
@ -0,0 +1,28 @@
|
|||
* Copyright (c) 2007-2011, All-Seeing Interactive
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the All-Seeing Interactive nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY All-Seeing Interactive ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL All-Seeing Interactive BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
A different license may apply to other software included in this package,
|
||||
including GHUnit and Andrew Donoho's Reachability class. Please consult their
|
||||
respective headers for the terms of their individual licenses.
|
32
Pods/ASIHTTPRequest/README.textile
generated
Normal file
32
Pods/ASIHTTPRequest/README.textile
generated
Normal file
|
@ -0,0 +1,32 @@
|
|||
ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications.
|
||||
|
||||
It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files using multipart/form-data.
|
||||
|
||||
It provides:
|
||||
* A straightforward interface for submitting data to and fetching data from webservers
|
||||
* Download data to memory or directly to a file on disk
|
||||
* Submit files on local drives as part of POST data, compatible with the HTML file input mechanism
|
||||
* Stream request bodies directly from disk to the server, to conserve memory
|
||||
* Resume for partial downloads
|
||||
* Easy access to request and response HTTP headers
|
||||
* Progress delegates (NSProgressIndicators and UIProgressViews) to show information about download AND upload progress
|
||||
* Auto-magic management of upload and download progress indicators for operation queues
|
||||
* Basic, Digest + NTLM authentication support, credentials are automatically re-used for the duration of a session, and can be stored for later in the Keychain.
|
||||
* Cookie support
|
||||
* [NEW] Requests can continue to run when your app moves to the background (iOS 4+)
|
||||
* GZIP support for response data AND request bodies
|
||||
* The included ASIDownloadCache class lets requests transparently cache responses, and allow requests for cached data to succeed even when there is no network available
|
||||
* [NEW] ASIWebPageRequest - download complete webpages, including external resources like images and stylesheets. Pages of any size can be indefinitely cached, and displayed in a UIWebview / WebView even when you have no network connection.
|
||||
* Easy to use support for Amazon S3 - no need to fiddle around signing requests yourself!
|
||||
* Full support for Rackspace Cloud Files
|
||||
* [NEW] Client certificates support
|
||||
* Supports manual and auto-detected proxies, authenticating proxies, and PAC file auto-configuration. The built-in login dialog lets your iPhone application work transparently with authenticating proxies without any additional effort.
|
||||
* Bandwidth throttling support
|
||||
* Support for persistent connections
|
||||
* Supports synchronous & asynchronous requests
|
||||
* Get notifications about changes in your request state via delegation or [NEW] blocks (Mac OS X 10.6, iOS 4 and above)
|
||||
* Comes with a broad range of unit tests
|
||||
|
||||
ASIHTTPRequest is compatible with Mac OS 10.5 or later, and iOS 3.0 or later.
|
||||
|
||||
Documentation is available "here":http://allseeing-i.com/ASIHTTPRequest.
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIAuthenticationDialog.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIAuthenticationDialog.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIAuthenticationDialog.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICacheDelegate.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICacheDelegate.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASICacheDelegate.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesCDNRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesCDNRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesCDNRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainer.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainer.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainer.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainerRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainerRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainerXMLParserDelegate.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesContainerXMLParserDelegate.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesObject.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesObject.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObject.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesObjectRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesObjectRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesObjectRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASICloudFilesRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/CloudFiles/ASICloudFilesRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDataCompressor.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDataCompressor.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIDataCompressor.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDataDecompressor.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDataDecompressor.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIDataDecompressor.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDownloadCache.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIDownloadCache.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIDownloadCache.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIFormDataRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIFormDataRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIFormDataRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIHTTPRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequestConfig.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequestConfig.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIHTTPRequestConfig.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequestDelegate.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIHTTPRequestDelegate.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIHTTPRequestDelegate.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIInputStream.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIInputStream.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIInputStream.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASINSXMLParserCompat.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASINSXMLParserCompat.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASINSXMLParserCompat.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASINetworkQueue.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASINetworkQueue.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASINetworkQueue.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIProgressDelegate.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIProgressDelegate.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIProgressDelegate.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3Bucket.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3Bucket.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3Bucket.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3BucketObject.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3BucketObject.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3BucketObject.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3BucketRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3BucketRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3BucketRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3ObjectRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3ObjectRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3ObjectRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3Request.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3Request.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3Request.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3ServiceRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIS3ServiceRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/S3/ASIS3ServiceRequest.h
|
1
Pods/BuildHeaders/ASIHTTPRequest/ASIWebPageRequest.h
generated
Symbolic link
1
Pods/BuildHeaders/ASIHTTPRequest/ASIWebPageRequest.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ASIHTTPRequest/Classes/ASIWebPageRequest/ASIWebPageRequest.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKAppSettingsViewController.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKAppSettingsViewController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKAppSettingsWebViewController.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKAppSettingsWebViewController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Controllers/IASKAppSettingsWebViewController.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSSliderSpecifierViewCell.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSSliderSpecifierViewCell.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKPSSliderSpecifierViewCell.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSTextFieldSpecifierViewCell.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSTextFieldSpecifierViewCell.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKPSTextFieldSpecifierViewCell.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSTitleValueSpecifierViewCell.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKPSTitleValueSpecifierViewCell.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKPSTitleValueSpecifierViewCell.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsReader.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsReader.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Models/IASKSettingsReader.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStore.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStore.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Models/IASKSettingsStore.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStoreFile.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStoreFile.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Models/IASKSettingsStoreFile.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStoreUserDefaults.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSettingsStoreUserDefaults.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Models/IASKSettingsStoreUserDefaults.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSlider.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSlider.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKSlider.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSpecifier.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSpecifier.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Models/IASKSpecifier.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSpecifierValuesViewController.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSpecifierValuesViewController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKSwitch.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKSwitch.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKSwitch.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKTextField.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKTextField.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Views/IASKTextField.h
|
1
Pods/BuildHeaders/InAppSettingsKit/IASKViewController.h
generated
Symbolic link
1
Pods/BuildHeaders/InAppSettingsKit/IASKViewController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../InAppSettingsKit/InAppSettingsKit/Controllers/IASKViewController.h
|
1
Pods/BuildHeaders/TMQuiltView/TMQuiltView.h
generated
Symbolic link
1
Pods/BuildHeaders/TMQuiltView/TMQuiltView.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../TMQuiltView/TMQuiltView/TMQuiltView/TMQuiltView.h
|
1
Pods/BuildHeaders/TMQuiltView/TMQuiltViewCell.h
generated
Symbolic link
1
Pods/BuildHeaders/TMQuiltView/TMQuiltViewCell.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../TMQuiltView/TMQuiltView/TMQuiltView/TMQuiltViewCell.h
|
1
Pods/BuildHeaders/TMQuiltView/TMQuiltViewController.h
generated
Symbolic link
1
Pods/BuildHeaders/TMQuiltView/TMQuiltViewController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../TMQuiltView/TMQuiltView/TMQuiltView/TMQuiltViewController.h
|
1
Pods/BuildHeaders/ViewDeck/IISideController.h
generated
Symbolic link
1
Pods/BuildHeaders/ViewDeck/IISideController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ViewDeck/ViewDeck/IISideController.h
|
1
Pods/BuildHeaders/ViewDeck/IIViewDeckController.h
generated
Symbolic link
1
Pods/BuildHeaders/ViewDeck/IIViewDeckController.h
generated
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../ViewDeck/ViewDeck/IIViewDeckController.h
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue