Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ci

  • Loading branch information...
commit ab4cc4604c9fb0355a327dda80bd82e01a15c7a3 1 parent 39e779b
@ddsakura authored
Showing with 15,363 additions and 0 deletions.
  1. +3 −0  .gitignore
  2. BIN  yahooOauth.xcodeproj/project.xcworkspace/xcuserdata/ddsakura.xcuserdatad/UserInterfaceState.xcuserstate
  3. +35 −0 yahooOauth/ASIHTTPRequest/ASIAuthenticationDialog.h
  4. +487 −0 yahooOauth/ASIHTTPRequest/ASIAuthenticationDialog.m
  5. +103 −0 yahooOauth/ASIHTTPRequest/ASICacheDelegate.h
  6. +42 −0 yahooOauth/ASIHTTPRequest/ASIDataCompressor.h
  7. +219 −0 yahooOauth/ASIHTTPRequest/ASIDataCompressor.m
  8. +41 −0 yahooOauth/ASIHTTPRequest/ASIDataDecompressor.h
  9. +218 −0 yahooOauth/ASIHTTPRequest/ASIDataDecompressor.m
  10. +46 −0 yahooOauth/ASIHTTPRequest/ASIDownloadCache.h
  11. +514 −0 yahooOauth/ASIHTTPRequest/ASIDownloadCache.m
  12. +76 −0 yahooOauth/ASIHTTPRequest/ASIFormDataRequest.h
  13. +361 −0 yahooOauth/ASIHTTPRequest/ASIFormDataRequest.m
  14. +1,004 −0 yahooOauth/ASIHTTPRequest/ASIHTTPRequest.h
  15. +5,107 −0 yahooOauth/ASIHTTPRequest/ASIHTTPRequest.m
  16. +37 −0 yahooOauth/ASIHTTPRequest/ASIHTTPRequestConfig.h
  17. +35 −0 yahooOauth/ASIHTTPRequest/ASIHTTPRequestDelegate.h
  18. +26 −0 yahooOauth/ASIHTTPRequest/ASIInputStream.h
  19. +138 −0 yahooOauth/ASIHTTPRequest/ASIInputStream.m
  20. +108 −0 yahooOauth/ASIHTTPRequest/ASINetworkQueue.h
  21. +343 −0 yahooOauth/ASIHTTPRequest/ASINetworkQueue.m
  22. +38 −0 yahooOauth/ASIHTTPRequest/ASIProgressDelegate.h
  23. +50 −0 yahooOauth/JSON/JSON.h
  24. +68 −0 yahooOauth/JSON/NSObject+SBJSON.h
  25. +53 −0 yahooOauth/JSON/NSObject+SBJSON.m
  26. +58 −0 yahooOauth/JSON/NSString+SBJSON.h
  27. +55 −0 yahooOauth/JSON/NSString+SBJSON.m
  28. +75 −0 yahooOauth/JSON/SBJSON.h
  29. +212 −0 yahooOauth/JSON/SBJSON.m
  30. +86 −0 yahooOauth/JSON/SBJsonBase.h
  31. +78 −0 yahooOauth/JSON/SBJsonBase.m
  32. +87 −0 yahooOauth/JSON/SBJsonParser.h
  33. +475 −0 yahooOauth/JSON/SBJsonParser.m
  34. +129 −0 yahooOauth/JSON/SBJsonWriter.h
  35. +237 −0 yahooOauth/JSON/SBJsonWriter.m
  36. +194 −0 yahooOauth/Reachability/Reachability.h
  37. +814 −0 yahooOauth/Reachability/Reachability.m
  38. +295 −0 yahooOauth/RegexKit/RegexKitLite.h
  39. +2,636 −0 yahooOauth/RegexKit/RegexKitLite.m
  40. +15 −0 yahooOauth/asiHttpRequestOauth/ASIFormDataRequest+OAuth.h
  41. +21 −0 yahooOauth/asiHttpRequestOauth/ASIFormDataRequest+OAuth.m
  42. +34 −0 yahooOauth/asiHttpRequestOauth/ASIHTTPRequest+OAuth.h
  43. +262 −0 yahooOauth/asiHttpRequestOauth/ASIHTTPRequest+OAuth.m
  44. +20 −0 yahooOauth/asiHttpRequestOauth/LICENSE
  45. +42 −0 yahooOauth/asiHttpRequestOauth/NSData+Base64.h
  46. +313 −0 yahooOauth/asiHttpRequestOauth/NSData+Base64.m
  47. +17 −0 yahooOauth/asiHttpRequestOauth/NSString+URLEncode.h
  48. +37 −0 yahooOauth/asiHttpRequestOauth/NSString+URLEncode.m
  49. +19 −0 yahooOauth/asiHttpRequestOauth/README
View
3  .gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+node_modules
+xcuserdata
View
BIN  yahooOauth.xcodeproj/project.xcworkspace/xcuserdata/ddsakura.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown
View
35 yahooOauth/ASIHTTPRequest/ASIAuthenticationDialog.h
@@ -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
View
487 yahooOauth/ASIHTTPRequest/ASIAuthenticationDialog.m
@@ -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 = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
+ CGFloat angle = 0;
+ switch (o) {
+ case UIDeviceOrientationLandscapeLeft: angle = 90; break;
+ case UIDeviceOrientationLandscapeRight: angle = -90; break;
+ case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
+ default: break;
+ }
+
+ CGRect f = [[UIScreen mainScreen] 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
View
103 yahooOauth/ASIHTTPRequest/ASICacheDelegate.h
@@ -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
View
42 yahooOauth/ASIHTTPRequest/ASIDataCompressor.h
@@ -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
View
219 yahooOauth/ASIHTTPRequest/ASIDataCompressor.m
@@ -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
View
41 yahooOauth/ASIHTTPRequest/ASIDataDecompressor.h
@@ -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
View
218 yahooOauth/ASIHTTPRequest/ASIDataDecompressor.m
@@ -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
View
46 yahooOauth/ASIHTTPRequest/ASIDownloadCache.h
@@ -0,0 +1,46 @@
+//
+// ASIDownloadCache.h
+// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
+//
+// Created by Ben Copsey on 01/05/2010.
+// Copyright 2010 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "ASICacheDelegate.h"
+
+@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
+
+ // The default cache policy for this cache
+ // Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy
+ // Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy
+ ASICachePolicy defaultCachePolicy;
+
+ // The directory in which cached data will be stored
+ // Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory
+ NSString *storagePath;
+
+ // Mediates access to the cache
+ NSRecursiveLock *accessLock;
+
+ // When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them
+ BOOL shouldRespectCacheControlHeaders;
+}
+
+// Returns a static instance of an ASIDownloadCache
+// In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache
+// To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
++ (id)sharedCache;
+
+// A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
++ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
+
+// A list of file extensions that we know won't be readable by a webview when accessed locally
+// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
++ (NSArray *)fileExtensionsToHandleAsHTML;
+
+@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
+@property (retain, nonatomic) NSString *storagePath;
+@property (retain) NSRecursiveLock *accessLock;
+@property (assign) BOOL shouldRespectCacheControlHeaders;
+@end
View
514 yahooOauth/ASIHTTPRequest/ASIDownloadCache.m
@@ -0,0 +1,514 @@
+//
+// ASIDownloadCache.m
+// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
+//
+// Created by Ben Copsey on 01/05/2010.
+// Copyright 2010 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIDownloadCache.h"
+#import "ASIHTTPRequest.h"
+#import <CommonCrypto/CommonHMAC.h>
+
+static ASIDownloadCache *sharedCache = nil;
+
+static NSString *sessionCacheFolder = @"SessionStore";
+static NSString *permanentCacheFolder = @"PermanentStore";
+static NSArray *fileExtensionsToHandleAsHTML = nil;
+
+@interface ASIDownloadCache ()
++ (NSString *)keyForURL:(NSURL *)url;
+- (NSString *)pathToFile:(NSString *)file;
+@end
+
+@implementation ASIDownloadCache
+
++ (void)initialize
+{
+ if (self == [ASIDownloadCache class]) {
+ // Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
+ // I imagine many web developers probably use url rewriting anyway
+ fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
+ }
+}
+
+- (id)init
+{
+ self = [super init];
+ [self setShouldRespectCacheControlHeaders:YES];
+ [self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
+ [self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
+ return self;
+}
+
++ (id)sharedCache
+{
+ if (!sharedCache) {
+ @synchronized(self) {
+ if (!sharedCache) {
+ sharedCache = [[self alloc] init];
+ [sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
+ }
+ }
+ }
+ return sharedCache;
+}
+
+- (void)dealloc
+{
+ [storagePath release];
+ [accessLock release];
+ [super dealloc];
+}
+
+- (NSString *)storagePath
+{
+ [[self accessLock] lock];
+ NSString *p = [[storagePath retain] autorelease];
+ [[self accessLock] unlock];
+ return p;
+}
+
+
+- (void)setStoragePath:(NSString *)path
+{
+ [[self accessLock] lock];
+ [self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
+ [storagePath release];
+ storagePath = [path retain];
+
+ NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
+
+ BOOL isDirectory = NO;
+ NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
+ for (NSString *directory in directories) {
+ BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory];
+ if (exists && !isDirectory) {
+ [[self accessLock] unlock];
+ [NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory];
+ } else if (!exists) {
+ [fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
+ if (![fileManager fileExistsAtPath:directory]) {
+ [[self accessLock] unlock];
+ [NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory];
+ }
+ }
+ }
+ [self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
+ [[self accessLock] unlock];
+}
+
+- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
+{
+ NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
+ NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath];
+ if (!cachedHeaders) {
+ return;
+ }
+ NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
+ if (!expires) {
+ return;
+ }
+ [cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
+ [cachedHeaders writeToFile:headerPath atomically:NO];
+}
+
+- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
+{
+ return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge];
+}
+
+- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
+{
+ [[self accessLock] lock];
+
+ if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) {
+ [[self accessLock] unlock];
+ return;
+ }
+
+ // We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection)
+ int responseCode = [request responseStatusCode];
+ if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
+ [[self accessLock] unlock];
+ return;
+ }
+
+ if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
+ [[self accessLock] unlock];
+ return;
+ }
+
+ NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
+ NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request];
+
+ NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
+ if ([request isResponseCompressed]) {
+ [responseHeaders removeObjectForKey:@"Content-Encoding"];
+ }
+
+ // Create a special 'X-ASIHTTPRequest-Expires' header
+ // This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time
+ // We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive
+
+ NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
+ if (expires) {
+ [responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
+ }
+
+ // Store the response code in a custom header so we can reuse it later
+
+ // We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET
+ int statusCode = [request responseStatusCode];
+ if (statusCode == 304) {
+ statusCode = 200;
+ }
+ [responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"];
+
+ [responseHeaders writeToFile:headerPath atomically:NO];
+
+ if ([request responseData]) {
+ [[request responseData] writeToFile:dataPath atomically:NO];
+ } else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
+ NSError *error = nil;
+ NSFileManager* manager = [[NSFileManager alloc] init];
+ if ([manager fileExistsAtPath:dataPath]) {
+ [manager removeItemAtPath:dataPath error:&error];
+ }
+ [manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
+ [manager release];
+ }
+ [[self accessLock] unlock];
+}
+
+- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url
+{
+ NSString *path = [self pathToCachedResponseHeadersForURL:url];
+ if (path) {
+ return [NSDictionary dictionaryWithContentsOfFile:path];
+ }
+ return nil;
+}
+
+- (NSData *)cachedResponseDataForURL:(NSURL *)url
+{
+ NSString *path = [self pathToCachedResponseDataForURL:url];
+ if (path) {
+ return [NSData dataWithContentsOfFile:path];
+ }
+ return nil;
+}
+
+- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url
+{
+ // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
+ NSString *extension = [[url path] pathExtension];
+
+ // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
+ // If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
+ if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
+ extension = @"html";
+ }
+ return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
+}
+
++ (NSArray *)fileExtensionsToHandleAsHTML
+{
+ return fileExtensionsToHandleAsHTML;
+}
+
+
+- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
+{
+ return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
+}
+
+- (NSString *)pathToFile:(NSString *)file
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return nil;
+ }
+
+ NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
+
+ // Look in the session store
+ NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file];
+ if ([fileManager fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return dataPath;
+ }
+ // Look in the permanent store
+ dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file];
+ if ([fileManager fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return dataPath;
+ }
+ [[self accessLock] unlock];
+ return nil;
+}
+
+
+- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return nil;
+ }
+
+ NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
+
+ // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
+ NSString *extension = [[[request url] path] pathExtension];
+
+ // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
+ // If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
+ if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
+ extension = @"html";
+ }
+ path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
+ [[self accessLock] unlock];
+ return path;
+}
+
+- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return nil;
+ }
+ NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
+ path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]];
+ [[self accessLock] unlock];
+ return path;
+}
+
+- (void)removeCachedDataForURL:(NSURL *)url
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
+
+ NSString *path = [self pathToCachedResponseHeadersForURL:url];
+ if (path) {
+ [fileManager removeItemAtPath:path error:NULL];
+ }
+
+ path = [self pathToCachedResponseDataForURL:url];
+ if (path) {
+ [fileManager removeItemAtPath:path error:NULL];
+ }
+ [[self accessLock] unlock];
+}
+
+- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
+{
+ [self removeCachedDataForURL:[request url]];
+}
+
+- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]];
+ if (!cachedHeaders) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
+ if (!dataPath) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+
+ // New content is not different
+ if ([request responseStatusCode] == 304) {
+ [[self accessLock] unlock];
+ return YES;
+ }
+
+ // If we already have response headers for this request, check to see if the new content is different
+ // We check [request complete] so that we don't end up comparing response headers from a redirection with these
+ if ([request responseHeaders] && [request complete]) {
+
+ // If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again
+ NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil];
+ for (NSString *header in headersToCompare) {
+ if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ }
+ }
+
+ if ([self shouldRespectCacheControlHeaders]) {
+
+ // Look for X-ASIHTTPRequest-Expires header to see if the content is out of date
+ NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"];
+ if (expires) {
+ if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) {
+ [[self accessLock] unlock];
+ return YES;
+ }
+ }
+
+ // No explicit expiration time sent by the server
+ [[self accessLock] unlock];
+ return NO;
+ }
+
+
+ [[self accessLock] unlock];
+ return YES;
+}
+
+- (ASICachePolicy)defaultCachePolicy
+{
+ [[self accessLock] lock];
+ ASICachePolicy cp = defaultCachePolicy;
+ [[self accessLock] unlock];
+ return cp;
+}
+
+
+- (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy
+{
+ [[self accessLock] lock];
+ if (!cachePolicy) {
+ defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy;
+ } else {
+ defaultCachePolicy = cachePolicy;
+ }
+ [[self accessLock] unlock];
+}
+
+- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
+
+ NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
+
+ BOOL isDirectory = NO;
+ BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
+ if (!exists || !isDirectory) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSError *error = nil;
+ NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
+ if (error) {
+ [[self accessLock] unlock];
+ [NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
+ }
+ for (NSString *file in cacheFiles) {
+ [fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
+ if (error) {
+ [[self accessLock] unlock];
+ [NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
+ }
+ }
+ [[self accessLock] unlock];
+}
+
++ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
+{
+ NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString];
+ if (cacheControl) {
+ if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) {
+ return NO;
+ }
+ }
+ NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString];
+ if (pragma) {
+ if ([pragma isEqualToString:@"no-cache"]) {
+ return NO;
+ }
+ }
+ return YES;
+}
+
++ (NSString *)keyForURL:(NSURL *)url
+{
+ NSString *urlString = [url absoluteString];
+ if ([urlString length] == 0) {
+ return nil;
+ }
+
+ // Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
+ if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
+ urlString = [urlString substringToIndex:[urlString length]-1];
+ }
+
+ // Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
+ const char *cStr = [urlString UTF8String];
+ unsigned char result[16];
+ CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
+ return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
+}
+
+- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request
+{
+ // Ensure the request is allowed to read from the cache
+ if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) {
+ return NO;
+
+ // If we don't want to load the request whatever happens, always pretend we have cached data even if we don't
+ } else if ([request cachePolicy] & ASIDontLoadCachePolicy) {
+ return YES;
+ }
+
+ NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]];
+ if (!headers) {
+ return NO;
+ }
+ NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
+ if (!dataPath) {
+ return NO;
+ }
+
+ // If we get here, we have cached data
+
+ // If we have cached data, we can use it
+ if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) {
+ return YES;
+
+ // If we want to fallback to the cache after an error
+ } else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) {
+ return YES;
+
+ // If we have cached data that is current, we can use it
+ } else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) {
+ if ([self isCachedDataCurrentForRequest:request]) {
+ return YES;
+ }
+
+ // If we've got headers from a conditional GET and the cached data is still current, we can use it
+ } else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) {
+ if (![request responseHeaders]) {
+ return NO;
+ } else if ([self isCachedDataCurrentForRequest:request]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+@synthesize storagePath;
+@synthesize defaultCachePolicy;
+@synthesize accessLock;
+@synthesize shouldRespectCacheControlHeaders;
+@end
View
76 yahooOauth/ASIHTTPRequest/ASIFormDataRequest.h
@@ -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:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
+
+// Add the contents of a local file to the request, clearing any others with the same key
+- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
+
+// Same as above, but you can specify the content-type and file name
+- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
+
+// Add the contents of an NSData object to the request
+- (void)addData:(NSData *)data forKey:(NSString *)key;
+
+// Same as above, but you can specify the content-type and file name
+- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
+
+// Add the contents of an NSData object to the request, clearing any others with the same key
+- (void)setData:(NSData *)data forKey:(NSString *)key;
+
+// Same as above, but you can specify the content-type and file name
+- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
+
+
+@property (assign) ASIPostFormat postFormat;
+@property (assign) NSStringEncoding stringEncoding;
+@end
View
361 yahooOauth/ASIHTTPRequest/ASIFormDataRequest.m
@@ -0,0 +1,361 @@
+//
+// 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(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 (!key) {
+ return;
+ }
+ if (![self postData]) {
+ [self setPostData:[NSMutableArray array]];
+ }
+ NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2];
+ [keyValuePair setValue:key forKey:@"key"];
+ [keyValuePair setValue:[value description] forKey:@"value"];
+ [[self postData] addObject:keyValuePair];
+}
+
+- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
+{
+ // Remove any existing value
+ NSUInteger i;
+ for (i=0; i<[[self postData] count]; i++) {
+ NSDictionary *val = [[self postData] objectAtIndex:i];
+ if ([[val objectForKey:@"key"] isEqualToString:key]) {
+ [[self postData] removeObjectAtIndex:i];
+ i--;
+ }
+ }
+ [self addPostValue:value forKey:key];
+}
+
+
+- (void)addFile:(NSString *)filePath forKey:(NSString *)key
+{
+ [self addFile:filePath withFileName:nil andContentType:nil forKey:key];
+}
+
+- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
+{
+ BOOL isDirectory = NO;
+ BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory];
+ if (!fileExists || isDirectory) {
+ [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]];
+ }
+
+ // If the caller didn't specify a custom file name, we'll use the file name of the file we were passed
+ if (!fileName) {
+ fileName = [filePath lastPathComponent];
+ }
+
+ // If we were given the path to a file, and the user didn't specify a mime type, we can detect it from the file extension
+ if (!contentType) {
+ contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath];
+ }
+ [self addData:filePath withFileName:fileName andContentType:contentType forKey:key];
+}
+
+- (void)setFile:(NSString *)filePath forKey:(NSString *)key
+{
+ [self setFile:filePath withFileName:nil andContentType:nil forKey:key];
+}
+
+- (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
+{
+ // Remove any existing value
+ NSUInteger i;
+ for (i=0; i<[[self fileData] count]; i++) {
+ NSDictionary *val = [[self fileData] objectAtIndex:i];
+ if ([[val objectForKey:@"key"] isEqualToString:key]) {
+ [[self fileData] removeObjectAtIndex:i];
+ i--;
+ }
+ }
+ [self addFile:data withFileName:fileName andContentType:contentType forKey:key];
+}
+
+- (void)addData:(NSData *)data forKey:(NSString *)key
+{
+ [self addData:data withFileName:@"file" andContentType:nil forKey:key];
+}
+
+- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
+{
+ if (![self fileData]) {
+ [self setFileData:[NSMutableArray array]];
+ }
+ if (!contentType) {
+ contentType = @"application/octet-stream";
+ }
+
+ NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4];
+ [fileInfo setValue:key forKey:@"key"];
+ [fileInfo setValue:fileName forKey:@"fileName"];
+ [fileInfo setValue:contentType forKey:@"contentType"];
+ [fileInfo setValue:data forKey:@"data"];
+
+ [[self fileData] addObject:fileInfo];
+}
+
+- (void)setData:(NSData *)data forKey:(NSString *)key
+{
+ [self setData:data withFileName:@"file" andContentType:nil forKey:key];
+}
+
+- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
+{
+ // Remove any existing value
+ NSUInteger i;
+ for (i=0; i<[[self fileData] count]; i++) {
+ NSDictionary *val = [[self fileData] objectAtIndex:i];
+ if ([[val objectForKey:@"key"] isEqualToString:key]) {
+ [[self fileData] removeObjectAtIndex:i];
+ i--;
+ }
+ }
+ [self addData:data withFileName:fileName andContentType:contentType forKey:key];
+}
+
+- (void)buildPostBody
+{
+ if ([self haveBuiltPostBody]) {
+ return;
+ }
+
+#if DEBUG_FORM_DATA_REQUEST
+ [self setDebugBodyString:@""];
+#endif
+
+ if (![self postData] && ![self fileData]) {
+ [super buildPostBody];
+ return;
+ }
+ if ([[self fileData] count] > 0) {
+ [self setShouldStreamPostDataFromDisk:YES];
+ }
+
+ if ([self postFormat] == ASIURLEncodedPostFormat) {
+ [self buildURLEncodedPostBody];
+ } else {
+ [self buildMultipartFormDataPostBody];
+ }
+
+ [super buildPostBody];
+
+#if DEBUG_FORM_DATA_REQUEST
+ 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]));
+
+ // We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
+ CFUUIDRef uuid = CFUUIDCreate(nil);
+ NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease];
+ CFRelease(uuid);
+ NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];
+
+ [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]];
+
+ [self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]];
+
+ // Adds post data
+ NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];
+ NSUInteger i=0;
+ for (NSDictionary *val in [self postData]) {
+ [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]];
+ [self appendPostString:[val objectForKey:@"value"]];
+ i++;
+ if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body
+ [self appendPostString:endItemBoundary];
+ }
+ }
+
+ // Adds files to upload
+ i=0;
+ for (NSDictionary *val in [self fileData]) {
+
+ [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]];
+ [self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]];
+
+ id data = [val objectForKey:@"data"];
+ if ([data isKindOfClass:[NSString class]]) {
+ [self appendPostDataFromFile:data];
+ } else {
+ [self appendPostData:data];
+ }
+ i++;
+ // Only add the boundary if this is not the last item in the post body
+ if (i != [[self fileData] count]) {
+ [self appendPostString:endItemBoundary];
+ }
+ }
+
+ [self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]];
+
+#if DEBUG_FORM_DATA_REQUEST
+ [self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"];
+#endif
+}
+
+- (void)buildURLEncodedPostBody
+{
+
+ // We can't post binary data using application/x-www-form-urlencoded
+ if ([[self fileData] count] > 0) {
+ [self setPostFormat:ASIMultipartFormDataPostFormat];
+ [self buildMultipartFormDataPostBody];
+ return;
+ }
+
+#if DEBUG_FORM_DATA_REQUEST
+ [self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"];
+#endif
+
+
+ NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
+
+ [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]];
+
+
+ NSUInteger i=0;
+ NSUInteger count = [[self postData] count]-1;
+ for (NSDictionary *val in [self postData]) {
+ NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i<count ? @"&" : @"")];
+ [self appendPostString:data];
+ i++;
+ }
+#if DEBUG_FORM_DATA_REQUEST
+ [self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
+#endif
+}
+
+- (void)appendPostString:(NSString *)string
+{
+#if DEBUG_FORM_DATA_REQUEST
+ [self addToDebugBody:string];
+#endif
+ [super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
+}
+
+#if DEBUG_FORM_DATA_REQUEST
+- (void)appendPostData:(NSData *)data
+{
+ [self addToDebugBody:[NSString stringWithFormat:@"[%lu bytes of data]",(unsigned long)[data length]]];
+ [super appendPostData:data];
+}
+
+- (void)appendPostDataFromFile:(NSString *)file
+{
+ NSError *err = nil;
+ unsigned long long fileSize = [[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:file error:&err] objectForKey:NSFileSize] unsignedLongLongValue];
+ if (err) {
+ [self addToDebugBody:[NSString stringWithFormat:@"[Error: Failed to obtain the size of the file at '%@']",file]];
+ } else {
+ [self addToDebugBody:[NSString stringWithFormat:@"[%llu bytes of data from file '%@']",fileSize,file]];
+ }
+
+ [super appendPostDataFromFile:file];
+}
+
+- (void)addToDebugBody:(NSString *)string
+{
+ if (string) {
+ [self setDebugBodyString:[[self debugBodyString] stringByAppendingString:string]];
+ }
+}
+#endif
+
+#pragma mark NSCopying
+
+- (id)copyWithZone:(NSZone *)zone
+{
+ ASIFormDataRequest *newRequest = [super copyWithZone:zone];
+ [newRequest setPostData:[[[self postData] mutableCopyWithZone:zone] autorelease]];
+ [newRequest setFileData:[[[self fileData] mutableCopyWithZone:zone] autorelease]];
+ [newRequest setPostFormat:[self postFormat]];
+ [newRequest setStringEncoding:[self stringEncoding]];
+ [newRequest setRequestMethod:[self requestMethod]];
+ return newRequest;
+}
+
+@synthesize postData;
+@synthesize fileData;
+@synthesize postFormat;
+@synthesize stringEncoding;
+#if DEBUG_FORM_DATA_REQUEST
+@synthesize debugBodyString;
+#endif
+@end
View
1,004 yahooOauth/ASIHTTPRequest/ASIHTTPRequest.h
@@ -0,0 +1,1004 @@
+//
+// 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