Browse files

Long overdue initial commit

  • Loading branch information...
0 parents commit b34fff58106002a0ab0b1996c35de8564a87ad19 @ndbroadbent committed Dec 29, 2010
Showing with 15,222 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +32 −0 Capfile
  3. +35 −0 Classes/External/ASI/ASIAuthenticationDialog.h
  4. +483 −0 Classes/External/ASI/ASIAuthenticationDialog.m
  5. +55 −0 Classes/External/ASI/ASICacheDelegate.h
  6. +47 −0 Classes/External/ASI/ASIDownloadCache.h
  7. +387 −0 Classes/External/ASI/ASIDownloadCache.m
  8. +76 −0 Classes/External/ASI/ASIFormDataRequest.h
  9. +355 −0 Classes/External/ASI/ASIFormDataRequest.m
  10. +832 −0 Classes/External/ASI/ASIHTTPRequest.h
  11. +4,058 −0 Classes/External/ASI/ASIHTTPRequest.m
  12. +32 −0 Classes/External/ASI/ASIHTTPRequestConfig.h
  13. +33 −0 Classes/External/ASI/ASIHTTPRequestDelegate.h
  14. +26 −0 Classes/External/ASI/ASIInputStream.h
  15. +136 −0 Classes/External/ASI/ASIInputStream.m
  16. +102 −0 Classes/External/ASI/ASINetworkQueue.h
  17. +322 −0 Classes/External/ASI/ASINetworkQueue.m
  18. +38 −0 Classes/External/ASI/ASIProgressDelegate.h
  19. +59 −0 Classes/External/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h
  20. +677 −0 Classes/External/InAppSettingsKit/Controllers/IASKAppSettingsViewController.m
  21. +34 −0 Classes/External/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.h
  22. +180 −0 Classes/External/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m
  23. +120 −0 Classes/External/InAppSettingsKit/Models/IASKSettingsReader.h
  24. +225 −0 Classes/External/InAppSettingsKit/Models/IASKSettingsReader.m
  25. +56 −0 Classes/External/InAppSettingsKit/Models/IASKSpecifier.h
  26. +220 −0 Classes/External/InAppSettingsKit/Models/IASKSpecifier.m
  27. +31 −0 Classes/External/InAppSettingsKit/Views/IASKPSSliderSpecifierViewCell.h
  28. +70 −0 Classes/External/InAppSettingsKit/Views/IASKPSSliderSpecifierViewCell.m
  29. +29 −0 Classes/External/InAppSettingsKit/Views/IASKPSTextFieldSpecifierViewCell.h
  30. +52 −0 Classes/External/InAppSettingsKit/Views/IASKPSTextFieldSpecifierViewCell.m
  31. +22 −0 Classes/External/InAppSettingsKit/Views/IASKPSTitleValueSpecifierViewCell.h
  32. +54 −0 Classes/External/InAppSettingsKit/Views/IASKPSTitleValueSpecifierViewCell.m
  33. +29 −0 Classes/External/InAppSettingsKit/Views/IASKPSToggleSwitchSpecifierViewCell.h
  34. +46 −0 Classes/External/InAppSettingsKit/Views/IASKPSToggleSwitchSpecifierViewCell.m
  35. +26 −0 Classes/External/InAppSettingsKit/Views/IASKSlider.h
  36. +29 −0 Classes/External/InAppSettingsKit/Views/IASKSlider.m
  37. +26 −0 Classes/External/InAppSettingsKit/Views/IASKSwitch.h
  38. +30 −0 Classes/External/InAppSettingsKit/Views/IASKSwitch.m
  39. +26 −0 Classes/External/InAppSettingsKit/Views/IASKTextField.h
  40. +29 −0 Classes/External/InAppSettingsKit/Views/IASKTextField.m
  41. +460 −0 Classes/External/InAppSettingsKit/Xibs/IASKAppSettingsView.xib
  42. +482 −0 Classes/External/InAppSettingsKit/Xibs/IASKPSSliderSpecifierViewCell.xib
  43. +309 −0 Classes/External/InAppSettingsKit/Xibs/IASKPSTextFieldSpecifierViewCell.xib
  44. +434 −0 Classes/External/InAppSettingsKit/Xibs/IASKPSToggleSwitchSpecifierViewCell.xib
  45. +408 −0 Classes/External/InAppSettingsKit/Xibs/IASKSpecifierValuesView.xib
  46. +193 −0 Classes/External/Reachability/Reachability.h
  47. +814 −0 Classes/External/Reachability/Reachability.m
  48. +23 −0 Classes/Flat_10C_AppDelegate.h
  49. +120 −0 Classes/Flat_10C_AppDelegate.m
  50. +32 −0 Classes/Flat_10C_ViewController.h
  51. +242 −0 Classes/Flat_10C_ViewController.m
  52. +65 −0 Classes/SlideToCancelViewController.h
  53. +374 −0 Classes/SlideToCancelViewController.m
  54. +539 −0 Flat 10C .xcodeproj/project.pbxproj
  55. +32 −0 Flat_10C_-Info.plist
  56. +679 −0 Flat_10C_ViewController.xib
  57. +8 −0 Flat_10C__Prefix.pch
  58. BIN Icon.png
  59. +823 −0 MainWindow.xib
  60. BIN Resources/Default.png
  61. BIN Resources/Default.xcf
  62. BIN Resources/Images/cross.png
  63. BIN Resources/Images/icon.xcf
  64. BIN Resources/Images/key-rotated-smallbw.xcf
  65. BIN Resources/Images/key-rotated.xcf
  66. BIN Resources/Images/key.png
  67. BIN Resources/Images/sliderThumb-blank.xcf
  68. BIN Resources/Images/sliderThumb.png
  69. BIN Resources/Images/sliderThumb.xcf
  70. BIN Resources/Images/sliderTrack.png
  71. BIN Resources/Images/tick.png
  72. +43 −0 Settings.bundle/Root.plist
  73. BIN Settings.bundle/en.lproj/Root.strings
  74. +17 −0 main.m
6 .gitignore
@@ -0,0 +1,6 @@
+Releases
+build
+*.mode1v3
+*.mode2v3
+*.pbxuser
+
32 Capfile
@@ -0,0 +1,32 @@
+set :application_name, "Flat 10C"
+set :iphone_hostname, "10.0.10.195"
+set :user, "root"
+set :escaped_name, application_name.gsub(" ", '\ ')
+set :build_dir, "/Users/nathanB/src/#{application_name}/build/Release-iphoneos"
+
+desc "Package your iPhone application"
+task :package do
+ puts "== Packaging application."
+ %x[cd "#{build_dir}" && \
+ tar -czpvf #{escaped_name}.tar.gz #{escaped_name}.app]
+ puts "== Transferring to iPhone (#{iphone_hostname}).."
+ %x[cd "#{build_dir}" && \
+ scp #{escaped_name}.tar.gz #{user}@#{iphone_hostname}:/Applications]
+ puts "===== Transferred."
+end
+
+desc "Install the application on your iPhone"
+task :install, :hosts => "#{iphone_hostname}" do
+ run <<-CMD
+ cd /Applications/;
+ tar -xzpvf #{escaped_name}.tar.gz;
+ rm #{escaped_name}.tar.gz;
+ killall SpringBoard; # OS 4.x
+ CMD
+end
+
+desc "Package and install the application on your iPhone"
+task :deploy, :hosts => "#{iphone_hostname}" do
+ package
+ install
+end
35 Classes/External/ASI/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
483 Classes/External/ASI/ASIAuthenticationDialog.m
@@ -0,0 +1,483 @@
+//
+// 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;
+@property (retain) UITableView *tableView;
+@end
+
+@implementation ASIAuthenticationDialog
+
+#pragma mark init / dealloc
+
++ (void)initialize
+{
+ if (self == [ASIAuthenticationDialog class]) {
+ requestsNeedingAuthentication = [[NSMutableArray array] retain];
+ }
+}
+
++ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request
+{
+ // No need for a lock here, this will always be called on the main thread
+ if (!sharedDialog) {
+ sharedDialog = [[self alloc] init];
+ [sharedDialog setRequest:request];
+ if ([request authenticationNeeded] == ASIProxyAuthenticationNeeded) {
+ [sharedDialog setType:ASIProxyAuthenticationType];
+ } else {
+ [sharedDialog setType:ASIStandardAuthenticationType];
+ }
+ [sharedDialog show];
+ } else {
+ [requestsNeedingAuthentication addObject:request];
+ }
+}
+
+- (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];
+
+ UIDeviceOrientation 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(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 presentNextDialog];
+ [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 *)tableView 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
55 Classes/External/ASI/ASICacheDelegate.h
@@ -0,0 +1,55 @@
+//
+// 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;
+
+typedef enum _ASICachePolicy {
+ ASIDefaultCachePolicy = 0,
+ ASIIgnoreCachePolicy = 1,
+ ASIReloadIfDifferentCachePolicy = 2,
+ ASIOnlyLoadIfNotCachedCachePolicy = 3,
+ ASIUseCacheIfLoadFailsCachePolicy = 4
+} ASICachePolicy;
+
+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 ASIDefaultCachePolicy
+- (ASICachePolicy)defaultCachePolicy;
+
+// Should Remove 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;
+
+// Should return an NSDictionary of cached headers for the passed request, if it is stored in the cache
+- (NSDictionary *)cachedHeadersForRequest:(ASIHTTPRequest *)request;
+
+// Should return the cached body of a response for the passed request, if it is stored in the cache
+- (NSData *)cachedResponseDataForRequest:(ASIHTTPRequest *)request;
+
+// Same as the above, but returns a path to the cached response body instead
+- (NSString *)pathToCachedResponseDataForRequest:(ASIHTTPRequest *)request;
+
+// Clear cached data stored for the passed storage policy
+- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy;
+@end
47 Classes/External/ASI/ASIDownloadCache.h
@@ -0,0 +1,47 @@
+//
+// 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 ASIDefaultCachePolicy
+ // Defaults to ASIReloadIfDifferentCachePolicy
+ 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 date formatter that can be used to construct an RFC 1123 date
+// The returned formatter is safe to use on the calling thread
+// Do not use this formatter for parsing dates because the format can vary slightly - use ASIHTTPRequest's dateFromRFC1123String: class method instead
++ (NSDateFormatter *)rfc1123DateFormatter;
+
+@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
+@property (retain, nonatomic) NSString *storagePath;
+@property (retain) NSRecursiveLock *accessLock;
+@property (assign) BOOL shouldRespectCacheControlHeaders;
+@end
387 Classes/External/ASI/ASIDownloadCache.m
@@ -0,0 +1,387 @@
+//
+// 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 *)keyForRequest:(ASIHTTPRequest *)request;
+@end
+
+@implementation ASIDownloadCache
+
+- (id)init
+{
+ self = [super init];
+ [self setShouldRespectCacheControlHeaders:YES];
+ [self setDefaultCachePolicy:ASIReloadIfDifferentCachePolicy];
+ [self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
+ return self;
+}
+
++ (id)sharedCache
+{
+ if (!sharedCache) {
+ sharedCache = [[self alloc] init];
+ [sharedCache setStoragePath:[NSTemporaryDirectory() 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];
+ BOOL isDirectory = NO;
+ NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
+ for (NSString *directory in directories) {
+ BOOL exists = [[NSFileManager defaultManager] 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) {
+ [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
+ if (![[NSFileManager defaultManager] 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)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
+{
+ [[self accessLock] lock];
+
+ if ([request error] || ![request responseHeaders] || ([request responseStatusCode] != 200)) {
+ [[self accessLock] unlock];
+ return;
+ }
+
+ if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
+ [[self accessLock] unlock];
+ return;
+ }
+
+ // If the request is set to use the default policy, use this cache's default policy
+ ASICachePolicy policy = [request cachePolicy];
+ if (policy == ASIDefaultCachePolicy) {
+ policy = [self defaultCachePolicy];
+ }
+
+ if (policy == ASIIgnoreCachePolicy) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSString *path = nil;
+ if ([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy) {
+ path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder];
+ } else {
+ path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder];
+ }
+ path = [path stringByAppendingPathComponent:[[self class] keyForRequest:request]];
+ NSString *metadataPath = [path stringByAppendingPathExtension:@"cachedheaders"];
+ NSString *dataPath = [path stringByAppendingPathExtension:@"cacheddata"];
+
+ NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
+ if ([request isResponseCompressed]) {
+ [responseHeaders removeObjectForKey:@"Content-Encoding"];
+ }
+ if (maxAge != 0) {
+ [responseHeaders removeObjectForKey:@"Expires"];
+ [responseHeaders setObject:[NSString stringWithFormat:@"max-age=%i",(int)maxAge] forKey:@"Cache-Control"];
+ }
+ // We use this special key to help expire the request when we get a max-age header
+ [responseHeaders setObject:[[[self class] rfc1123DateFormatter] stringFromDate:[NSDate date]] forKey:@"X-ASIHTTPRequest-Fetch-date"];
+ [responseHeaders writeToFile:metadataPath atomically:NO];
+
+ if ([request responseData]) {
+ [[request responseData] writeToFile:dataPath atomically:NO];
+ } else if ([request downloadDestinationPath]) {
+ NSError *error = nil;
+ [[NSFileManager defaultManager] copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
+ }
+ [[self accessLock] unlock];
+}
+
+- (NSDictionary *)cachedHeadersForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return nil;
+ }
+ // Look in the session store
+ NSString *path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder];
+ NSString *dataPath = [path stringByAppendingPathComponent:[[[self class] keyForRequest:request] stringByAppendingPathExtension:@"cachedheaders"]];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return [NSDictionary dictionaryWithContentsOfFile:dataPath];
+ }
+ // Look in the permanent store
+ path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder];
+ dataPath = [path stringByAppendingPathComponent:[[[self class] keyForRequest:request] stringByAppendingPathExtension:@"cachedheaders"]];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return [NSDictionary dictionaryWithContentsOfFile:dataPath];
+ }
+ [[self accessLock] unlock];
+ return nil;
+}
+
+- (NSData *)cachedResponseDataForRequest:(ASIHTTPRequest *)request
+{
+ NSString *path = [self pathToCachedResponseDataForRequest:request];
+ if (path) {
+ return [NSData dataWithContentsOfFile:path];
+ }
+ return nil;
+}
+
+- (NSString *)pathToCachedResponseDataForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return nil;
+ }
+ // Look in the session store
+ NSString *path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder];
+ NSString *dataPath = [path stringByAppendingPathComponent:[[[self class] keyForRequest:request] stringByAppendingPathExtension:@"cacheddata"]];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return dataPath;
+ }
+ // Look in the permanent store
+ path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder];
+ dataPath = [path stringByAppendingPathComponent:[[[self class] keyForRequest:request] stringByAppendingPathExtension:@"cacheddata"]];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
+ [[self accessLock] unlock];
+ return dataPath;
+ }
+ [[self accessLock] unlock];
+ return nil;
+}
+
+- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSString *cachedHeadersPath = [[self storagePath] stringByAppendingPathComponent:[[[self class] keyForRequest:request] stringByAppendingPathExtension:@"cachedheaders"]];
+ if (!cachedHeadersPath) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSString *dataPath = [self pathToCachedResponseDataForRequest:request];
+ if (!dataPath) {
+ [[self accessLock] unlock];
+ return;
+ }
+ [[NSFileManager defaultManager] removeItemAtPath:cachedHeadersPath error:NULL];
+ [[NSFileManager defaultManager] removeItemAtPath:dataPath error:NULL];
+ [[self accessLock] unlock];
+}
+
+- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ NSDictionary *cachedHeaders = [self cachedHeadersForRequest:request];
+ if (!cachedHeaders) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ NSString *dataPath = [self pathToCachedResponseDataForRequest:request];
+ if (!dataPath) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+
+ if ([self shouldRespectCacheControlHeaders]) {
+
+ // Look for an Expires header to see if the content is out of data
+ NSString *expires = [cachedHeaders objectForKey:@"Expires"];
+ if (expires) {
+ if ([[ASIHTTPRequest dateFromRFC1123String:expires] timeIntervalSinceNow] < 0) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ }
+ // Look for a max-age header
+ NSString *cacheControl = [[cachedHeaders objectForKey:@"Cache-Control"] lowercaseString];
+ if (cacheControl) {
+ NSScanner *scanner = [NSScanner scannerWithString:cacheControl];
+ if ([scanner scanString:@"max-age" intoString:NULL]) {
+ [scanner scanString:@"=" intoString:NULL];
+ NSTimeInterval maxAge = 0;
+ [scanner scanDouble:&maxAge];
+ NSDate *fetchDate = [ASIHTTPRequest dateFromRFC1123String:[cachedHeaders objectForKey:@"X-ASIHTTPRequest-Fetch-date"]];
+
+ NSDate *expiryDate = [[[NSDate alloc] initWithTimeInterval:maxAge sinceDate:fetchDate] autorelease];
+
+ if ([expiryDate timeIntervalSinceNow] < 0) {
+ [[self accessLock] unlock];
+ return NO;
+ }
+ }
+ }
+
+ }
+
+ // If we already have response headers for this request, check to see if the new content is different
+ if ([request responseHeaders] && [request responseStatusCode] != 304) {
+ // If the Etag or Last-Modified date are different from the one we have, fetch the document 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;
+ }
+ }
+ }
+ [[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 == ASIDefaultCachePolicy) {
+ defaultCachePolicy = ASIReloadIfDifferentCachePolicy;
+ } else {
+ defaultCachePolicy = cachePolicy;
+ }
+ [[self accessLock] unlock];
+}
+
+- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
+{
+ [[self accessLock] lock];
+ if (![self storagePath]) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSString *path;
+ if (storagePolicy == ASICachePermanentlyCacheStoragePolicy) {
+ path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder];
+ } else {
+ path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder];
+ }
+ BOOL isDirectory = NO;
+ BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory];
+ if (exists && !isDirectory || !exists) {
+ [[self accessLock] unlock];
+ return;
+ }
+ NSError *error = nil;
+ NSArray *cacheFiles = [[NSFileManager defaultManager] 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) {
+ NSString *extension = [file pathExtension];
+ if ([extension isEqualToString:@"cacheddata"] || [extension isEqualToString:@"cachedheaders"]) {
+ [[NSFileManager defaultManager] 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 *)keyForRequest:(ASIHTTPRequest *)request
+{
+ const char *cStr = [[[request url] absoluteString] 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]];
+}
+
++ (NSDateFormatter *)rfc1123DateFormatter
+{
+ NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
+ NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASIDownloadCacheDateFormatter"];
+ if (dateFormatter == nil) {
+ dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
+ [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+ [dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss 'GMT'"];
+ [threadDict setObject:dateFormatter forKey:@"ASIDownloadCacheDateFormatter"];
+ }
+ return dateFormatter;
+}
+
+
+@synthesize storagePath;
+@synthesize defaultCachePolicy;
+@synthesize accessLock;
+@synthesize shouldRespectCacheControlHeaders;
+@end
76 Classes/External/ASI/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:(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 Classes/External/ASI/ASIFormDataRequest.m
@@ -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 defaultManager] 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 defaultManager] 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
832 Classes/External/ASI/ASIHTTPRequest.h
@@ -0,0 +1,832 @@
+//
+// ASIHTTPRequest.h
+//
+// Created by Ben Copsey on 04/10/2007.
+// Copyright 2007-2010 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>
+#endif
+#import <stdio.h>
+#import "ASIHTTPRequestConfig.h"
+#import "ASIHTTPRequestDelegate.h"
+#import "ASIProgressDelegate.h"
+#import "ASICacheDelegate.h"
+
+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
+
+} 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;
+
+@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;
+
+ // The delegate, you need to manage setting and talking to your delegate in your subclasses
+ 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
+ id <ASIHTTPRequestDelegate, ASIProgressDelegate> queue;
+
+ // HTTP method to use (GET / POST / PUT / DELETE / HEAD). 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;
+
+ // Used for writing data to a file when downloadDestinationPath is set
+ NSOutputStream *fileDownloadOutputStream;
+
+ // When the request fails or completes successfully, complete will be true
+ BOOL complete;
+
+ // 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;
+
+ // 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)
+ 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 requestDidReceiveResponseHeaders:
+ SEL didReceiveResponseHeadersSelector;
+
+ // 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
+ NSDictionary *userInfo;
+
+ // 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;
+
+ // 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
+ 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;
+
+ // 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;
+}
+
+#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;
+
+#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;
+
+#pragma mark request logic
+
+// Call to delete the temporary file used during a file download (if it exists)
+// No need to call this if the request succeeds - it is removed automatically
+- (void)removeTemporaryDownloadFile;
+
+// Call to remove the file used as the request body
+// No need to call this if the request succeeds and you didn't specify postBodyFilePath manually - it is removed automatically
+- (void)removePostDataFile;
+
+#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;
+
+#pragma mark handling request complete / failure
+
+// 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;
+
+// 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;
+
+#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;
+
+#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 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 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 gzip decompression
+
+// Uncompress gzipped data with zlib
++ (NSData *)uncompressZippedData:(NSData*)compressedData;
+
+// Uncompress gzipped data from a file into another file, used when downloading to a file
++ (int)uncompressZippedDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath;
++ (int)uncompressZippedDataFromSource:(FILE *)source toDestination:(FILE *)dest;
+
+#pragma mark gzip compression
+
+// Compress data with gzip using zlib
++ (NSData *)compressData:(NSData*)uncompressedData;
+
+// gzip compress data from a file, saving to another file, used for uploading when shouldCompressRequestBody is true
++ (int)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath;
++ (int)compressDataFromSource:(FILE *)source toDestination:(FILE *)dest;
+
+#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;
+
+#pragma mark proxy autoconfiguration
+
+// Returns an array of proxies to use for a particular url, given the url of a PAC script
++ (NSArray *)proxiesForURL:(NSURL *)theURL fromPAC:(NSURL *)pacScriptURL;
+
+#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 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;
+#if TARGET_OS_IPHONE
++ (void)setShouldUpdateNetworkActivityIndicator:(BOOL)shouldUpdate;
+#endif
+
+#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;
+
+#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 *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:) NSURL *url;
+@property (retain) NSURL *originalURL;
+@property (assign, nonatomic) id delegate;
+@property (assign, 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 (assign) SEL didStartSelector;
+@property (assign) SEL didReceiveResponseHeadersSelector;
+@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) NSString *requestMethod;
+@property (retain) NSMutableData *postBody;
+@property (assign,readonly) 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,readonly) unsigned long long totalBytesRead;
+@property (assign,readonly) unsigned long long totalBytesSent;
+@property (assign) NSStringEncoding defaultResponseEncoding;
+@property (assign,readonly) NSStringEncoding responseEncoding;
+@property (assign) BOOL allowCompressedResponse;
+@property (assign) BOOL allowResumeForFileDownloads;
+@property (retain) NSDictionary *userInfo;
+@property (retain) NSString *postBodyFilePath;
+@property (assign) BOOL shouldStreamPostDataFromDisk;