Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of github.com:schacon/igithub

  • Loading branch information...
commit dc0a13494aa038e67906f092c2fdc4ae6dd87b93 2 parents 3d3f9d0 + c9bc384
@schacon authored
Showing with 22,409 additions and 783 deletions.
  1. BIN  .DS_Store
  2. +4 −11 { → Classes}/AppController.h
  3. +117 −0 Classes/AppController.m
  4. 0  {Networking → Classes}/BrowserViewController.h
  5. 0  {Networking → Classes}/BrowserViewController.m
  6. 0  { → Classes}/CommitDetailViewController.h
  7. 0  { → Classes}/CommitDetailViewController.m
  8. +3 −3 { → Classes}/CommitsViewController.h
  9. +1 −1  { → Classes}/CommitsViewController.m
  10. 0  { → Classes}/ProjectController.h
  11. +5 −5 { → Classes}/ProjectController.m
  12. +3 −3 { → Classes}/ProjectDetailViewController.h
  13. +6 −6 { → Classes}/ProjectDetailViewController.m
  14. +1 −0  { → Classes}/ProjectViewController.h
  15. +2 −4 { → Classes}/ProjectViewController.m
  16. 0  { → Classes}/ServerViewController.h
  17. 0  { → Classes}/ServerViewController.m
  18. +28 −0 Client/ASIAuthenticationDialog.h
  19. +236 −0 Client/ASIAuthenticationDialog.m
  20. +61 −0 Client/ASIFormDataRequest.h
  21. +300 −0 Client/ASIFormDataRequest.m
  22. +654 −0 Client/ASIHTTPRequest.h
  23. +3,236 −0 Client/ASIHTTPRequest.m
  24. +29 −0 Client/ASIHTTPRequestConfig.h
  25. +22 −0 Client/ASIInputStream.h
  26. +103 −0 Client/ASIInputStream.m
  27. +16 −0 Client/ASINSStringAdditions.h
  28. +28 −0 Client/ASINSStringAdditions.m
  29. +120 −0 Client/ASINetworkQueue.h
  30. +349 −0 Client/ASINetworkQueue.m
  31. +88 −0 Client/Reachability.h
  32. +274 −0 Client/Reachability.m
  33. +37 −0 CocoaGit/Core/GITBlob.h
  34. +92 −0 CocoaGit/Core/GITBlob.m
  35. +49 −0 CocoaGit/Core/GITCommit.h
  36. +302 −0 CocoaGit/Core/GITCommit.m
  37. +25 −0 CocoaGit/Core/GITObject+Parsing.h
  38. +82 −0 CocoaGit/Core/GITObject+Parsing.m
  39. +192 −0 CocoaGit/Core/GITObject.h
  40. +194 −0 CocoaGit/Core/GITObject.m
  41. +37 −0 CocoaGit/Core/GITTag.h
  42. +179 −0 CocoaGit/Core/GITTag.m
  43. +24 −0 CocoaGit/Core/GITTree.h
  44. +108 −0 CocoaGit/Core/GITTree.m
  45. +93 −0 CocoaGit/Core/GITTreeEntry.h
  46. +141 −0 CocoaGit/Core/GITTreeEntry.m
  47. +61 −0 CocoaGit/Extra/GITActor.h
  48. +87 −0 CocoaGit/Extra/GITActor.m
  49. +34 −0 CocoaGit/Extra/GITDateTime.h
  50. +85 −0 CocoaGit/Extra/GITDateTime.m
  51. +50 −0 CocoaGit/Extra/GITErrors.h
  52. +38 −0 CocoaGit/Extra/GITErrors.m
  53. +20 −0 CocoaGit/Extra/GITUtilityBelt.h
  54. +169 −0 CocoaGit/Extra/GITUtilityBelt.m
  55. +230 −0 CocoaGit/GITRepo.h
  56. +382 −0 CocoaGit/GITRepo.m
  57. +25 −0 CocoaGit/Git.h
  58. +29 −0 CocoaGit/Graph/GITCommitEnumerator.h
  59. +122 −0 CocoaGit/Graph/GITCommitEnumerator.m
  60. +36 −0 CocoaGit/Graph/GITGraph.h
  61. +231 −0 CocoaGit/Graph/GITGraph.m
  62. +51 −0 CocoaGit/Graph/GITNode.h
  63. +128 −0 CocoaGit/Graph/GITNode.m
  64. +16 −0 CocoaGit/Graph/GITRepo+Enumerators.h
  65. +22 −0 CocoaGit/Graph/GITRepo+Enumerators.m
  66. +178 −0 CocoaGit/Pack/GITPackFile.h
  67. +119 −0 CocoaGit/Pack/GITPackFile.m
  68. +25 −0 CocoaGit/Pack/GITPackFileVersion2.h
  69. +291 −0 CocoaGit/Pack/GITPackFileVersion2.m
  70. +196 −0 CocoaGit/Pack/GITPackIndex.h
  71. +177 −0 CocoaGit/Pack/GITPackIndex.m
  72. +23 −0 CocoaGit/Pack/GITPackIndexVersion1.h
  73. +232 −0 CocoaGit/Pack/GITPackIndexVersion1.m
  74. +26 −0 CocoaGit/Pack/GITPackIndexVersion2.h
  75. +343 −0 CocoaGit/Pack/GITPackIndexVersion2.m
  76. +23 −0 CocoaGit/Pack/GITPackReverseIndex.h
  77. +162 −0 CocoaGit/Pack/GITPackReverseIndex.m
  78. +15 −0 CocoaGit/Pack/GITPlaceholderPackFile.h
  79. +89 −0 CocoaGit/Pack/GITPlaceholderPackFile.m
  80. +16 −0 CocoaGit/Pack/GITPlaceholderPackIndex.h
  81. +57 −0 CocoaGit/Pack/GITPlaceholderPackIndex.m
  82. +22 −0 CocoaGit/Refs/GITBranch.h
  83. +44 −0 CocoaGit/Refs/GITBranch.m
  84. +41 −0 CocoaGit/Refs/GITRef.h
  85. +168 −0 CocoaGit/Refs/GITRef.m
  86. +73 −0 CocoaGit/Store/GITCombinedStore.h
  87. +150 −0 CocoaGit/Store/GITCombinedStore.m
  88. +28 −0 CocoaGit/Store/GITFileStore.h
  89. +138 −0 CocoaGit/Store/GITFileStore.m
  90. +121 −0 CocoaGit/Store/GITObjectStore.h
  91. +87 −0 CocoaGit/Store/GITObjectStore.m
  92. +69 −0 CocoaGit/Store/GITPackStore.h
  93. +157 −0 CocoaGit/Store/GITPackStore.m
  94. +50 −0 CocoaGit/Store/GITRefStore.h
  95. +291 −0 CocoaGit/Store/GITRefStore.m
  96. +14 −0 CocoaGit/Util/NSCharacterSet+StringComparison.h
  97. +19 −0 CocoaGit/Util/NSCharacterSet+StringComparison.m
  98. +42 −0 CocoaGit/Util/NSData+Compression.h
  99. +191 −0 CocoaGit/Util/NSData+Compression.m
  100. +28 −0 CocoaGit/Util/NSData+Hashing.h
  101. +56 −0 CocoaGit/Util/NSData+Hashing.m
  102. +40 −0 CocoaGit/Util/NSData+HexDump.h
  103. +114 −0 CocoaGit/Util/NSData+HexDump.m
  104. +18 −0 CocoaGit/Util/NSData+Patching.h
  105. +92 −0 CocoaGit/Util/NSData+Patching.m
  106. +46 −0 CocoaGit/Util/NSData+Searching.h
  107. +42 −0 CocoaGit/Util/NSData+Searching.m
  108. +73 −0 CocoaGit/Util/NSError-OBExtensions.h
  109. +263 −0 CocoaGit/Util/NSError-OBExtensions.m
  110. +15 −0 CocoaGit/Util/NSFileManager+DirHelper.h
  111. +40 −0 CocoaGit/Util/NSFileManager+DirHelper.m
  112. +27 −0 CocoaGit/Util/NSTimeZone+Offset.h
  113. +45 −0 CocoaGit/Util/NSTimeZone+Offset.m
  114. +134 −0 CocoaGit/Util/assertions.h
  115. +100 −0 CocoaGit/Util/assertions.m
  116. +71 −0 Controllers/AppController.h
  117. +19 −75 { → Controllers}/AppController.m
  118. +96 −0 Controllers/BrowserViewController.h
  119. +404 −0 Controllers/BrowserViewController.m
  120. +20 −0 Controllers/CommitDetailViewController.h
  121. +255 −0 Controllers/CommitDetailViewController.m
  122. +24 −0 Controllers/CommitsViewController.h
  123. +231 −0 Controllers/CommitsViewController.m
  124. +22 −0 Controllers/GitHTTPConnection.h
  125. +262 −0 Controllers/GitHTTPConnection.m
  126. +16 −0 Controllers/ProjectController.h
  127. +52 −0 Controllers/ProjectController.m
  128. +15 −0 Controllers/ProjectDetailViewController.h
  129. +113 −0 Controllers/ProjectDetailViewController.m
  130. +17 −0 Controllers/ProjectViewController.h
  131. +111 −0 Controllers/ProjectViewController.m
  132. +20 −0 Controllers/ServerViewController.h
  133. +81 −0 Controllers/ServerViewController.m
  134. +0 −15 Git/NSDataCompression.h
  135. +0 −80 Git/NSDataCompression.m
  136. +1 −1  Git/ObjGit.m
  137. +1 −1  Git/ObjGitObject.m
  138. +1 −1  Git/ObjGitServerHandler.m
  139. +0 −13 GitTest.h
  140. +0 −14 GitTest.m
  141. +409 −0 Http/AsyncSocket.h
  142. +2,935 −0 Http/AsyncSocket.m
  143. +14 −0 Http/DDData.h
  144. +203 −0 Http/DDData.m
  145. +12 −0 Http/DDNumber.h
  146. +74 −0 Http/DDNumber.m
  147. +52 −0 Http/DDRange.h
  148. +70 −0 Http/DDRange.m
  149. +43 −0 Http/HTTPAuthenticationRequest.h
  150. +208 −0 Http/HTTPAuthenticationRequest.m
  151. +67 −0 Http/HTTPConnection.h
  152. +1,506 −0 Http/HTTPConnection.m
  153. +41 −0 Http/HTTPResponse.h
  154. +104 −0 Http/HTTPResponse.m
  155. +59 −0 Http/HTTPServer.h
  156. +350 −0 Http/HTTPServer.m
  157. +0 −54 Networking/TCPServer.h
  158. +0 −242 Networking/TCPServer.m
  159. +0 −27 Picker.h
  160. +0 −117 Picker.m
  161. +35 −4 TODO
  162. 0  { → assets}/Default.png
  163. 0  { → assets}/bg.png
  164. 0  { → assets}/icon.png
  165. 0  { → assets}/octocat.png
  166. 0  { → assets}/rssicon.png
  167. 0  { → assets}/server.png
  168. 0  { → assets}/servericon.png
  169. 0  { → assets}/test.png
  170. +527 −106 iGitHub.xcodeproj/project.pbxproj
  171. +1 −0  main.m
View
BIN  .DS_Store
Binary file not shown
View
15 AppController.h → Classes/AppController.h
@@ -48,22 +48,15 @@ Copyright (C) 2008 Apple Inc. All Rights Reserved.
#import "BrowserViewController.h"
#import "ServerViewController.h"
-#import "TCPServer.h"
-#import "ObjGitCommit.h"
//CLASS INTERFACES:
-@interface AppController : NSObject <UIApplicationDelegate, UITabBarControllerDelegate, TCPServerDelegate>
+@interface AppController : NSObject <UIApplicationDelegate, UITabBarControllerDelegate>
{
UIWindow* _window;
- TCPServer* _server;
- NSInputStream* _inStream;
- NSOutputStream* _outStream;
- BOOL _inReady;
- BOOL _outReady;
- UINavigationController *navigationController;
- UITabBarController *tabBarController;
- ServerViewController *serverViewController;
+ UINavigationController *navigationController;
+ UITabBarController *tabBarController;
+ ServerViewController *serverViewController;
NSString* gitDir;
}
View
117 Classes/AppController.m
@@ -0,0 +1,117 @@
+/*
+
+File: AppController.m
+Abstract: UIApplication's delegate class, the central controller of the
+application.
+
+Version: 1.5
+
+*/
+
+#import "AppController.h"
+#import "ProjectViewController.h"
+#import "ProjectController.h"
+#import "ServerViewController.h"
+
+#define bonIdentifier @"git"
+
+//INTERFACES:
+
+@interface AppController ()
+
+@property (assign, readwrite) NSString *gitDir;
+
+- (void) setup;
+
+@end
+
+//CLASS IMPLEMENTATIONS:
+
+@implementation AppController
+
+@synthesize gitDir;
+@synthesize navigationController;
+@synthesize tabBarController;
+@synthesize serverViewController;
+
+- (NSString *)getGitPath
+{
+ NSArray *paths;
+ NSString *gitPath = @"";
+ paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ if ([paths count] > 0) {
+ gitPath = [NSString stringWithString:[[paths objectAtIndex:0] stringByAppendingPathComponent:@"git"]];
+
+ BOOL isDir;
+ NSFileManager *fm = [NSFileManager defaultManager];
+ if (![fm fileExistsAtPath:gitPath isDirectory:&isDir] && isDir) {
+ [fm createDirectoryAtPath:gitPath attributes:nil];
+ }
+ }
+ return gitPath;
+}
+
+- (void) applicationDidFinishLaunching:(UIApplication*)application
+{
+ NSString * thisHostName = [[NSProcessInfo processInfo] hostName];
+ NSLog(@"hostname: %@", thisHostName);
+ // Create a full-screen window
+ _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+
+ // getting the git path
+ gitDir = [self getGitPath];
+
+ // Create and configure the navigation and view controllers
+ ProjectController *pController = [[ProjectController alloc] init];
+ [pController readProjects:gitDir];
+
+ ProjectViewController *projectViewController = [[ProjectViewController alloc] initWithStyle:UITableViewStylePlain];
+ [projectViewController setProjectController:pController];
+
+ ServerViewController *serverController = [[ServerViewController alloc] init];
+ self.serverViewController = serverController;
+
+ UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:projectViewController];
+ self.navigationController = aNavigationController;
+
+ UITabBarController *atabBarController = [[UITabBarController alloc] init];
+ NSArray *vc = [NSArray arrayWithObjects:navigationController, serverViewController, nil];
+ [atabBarController setViewControllers:vc animated:NO];
+ self.tabBarController = atabBarController;
+
+ // Configure and show the window
+ [_window addSubview:tabBarController.view];
+ [_window makeKeyAndVisible];
+
+ [projectViewController release];
+ [aNavigationController release];
+
+ [self setup];
+}
+
+- (void) dealloc
+{
+ NSLog(@"dealloc");
+ [_window release];
+ [super dealloc];
+}
+
+- (void) setup {
+ // TODO: setup the http server
+ NSLog(@"Setup");
+
+ gitDir = [self getGitPath];
+
+ BOOL isDir=NO;
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if ([fileManager fileExistsAtPath:gitDir isDirectory:&isDir] && isDir) {
+ NSEnumerator *e = [[fileManager directoryContentsAtPath:gitDir] objectEnumerator];
+ NSString *thisDir;
+ while ( (thisDir = [e nextObject]) ) {
+ NSLog(@"announce:%@", thisDir);
+ // TODO: announce http over bonjour
+ }
+ }
+}
+
+@end
View
0  Networking/BrowserViewController.h → Classes/BrowserViewController.h
File renamed without changes
View
0  Networking/BrowserViewController.m → Classes/BrowserViewController.m
File renamed without changes
View
0  CommitDetailViewController.h → Classes/CommitDetailViewController.h
File renamed without changes
View
0  CommitDetailViewController.m → Classes/CommitDetailViewController.m
File renamed without changes
View
6 CommitsViewController.h → Classes/CommitsViewController.h
@@ -4,16 +4,16 @@
//
#import <UIKit/UIKit.h>
-#import "ObjGit.h"
+#import "Git.h"
@interface CommitsViewController : UITableViewController {
- ObjGit *gitRepo;
+ GITRepo *gitRepo;
NSString *gitRef;
NSString *gitSha;
NSMutableArray *commitList;
}
-@property (nonatomic, retain) ObjGit *gitRepo;
+@property (nonatomic, retain) GITRepo *gitRepo;
@property (nonatomic, retain) NSString *gitRef;
@property (nonatomic, retain) NSString *gitSha;
@property (nonatomic, retain) NSMutableArray *commitList;
View
2  CommitsViewController.m → Classes/CommitsViewController.m
@@ -5,7 +5,7 @@
#import "CommitsViewController.h"
#import "CommitDetailViewController.h"
-#import "ObjGitCommit.h"
+#import "Git.h"
#define ROW_HEIGHT 60
View
0  ProjectController.h → Classes/ProjectController.h
File renamed without changes
View
10 ProjectController.m → Classes/ProjectController.m
@@ -4,7 +4,7 @@
//
#import "ProjectController.h"
-#import "ObjGit.h"
+#import "Git.h"
@interface ProjectController ()
@property (nonatomic, copy, readwrite) NSMutableArray *list;
@@ -17,7 +17,7 @@ @implementation ProjectController
// Custom set accessor to ensure the new list is mutable
- (void)readProjects:(NSString *)projectPath
{
- //NSLog(@"READ PROJECTS:%@", projectPath);
+ NSLog(@"READ PROJECTS:%@", projectPath);
BOOL isDir=NO;
[list release];
list = [[NSMutableArray alloc] init];
@@ -27,9 +27,9 @@ - (void)readProjects:(NSString *)projectPath
NSString *thisDir;
while ( (thisDir = [e nextObject]) ) {
NSString *dir = [projectPath stringByAppendingPathComponent:thisDir];
- ObjGit* git = [[ObjGit alloc] init];
- [git openRepo:dir];
- [git setGitName:thisDir];
+ GITRepo* git = [[GITRepo alloc] init];
+ [git initWithRoot:dir];
+ [git setDesc:thisDir];
[list addObject:git];
}
}
View
6 ProjectDetailViewController.h → Classes/ProjectDetailViewController.h
@@ -4,12 +4,12 @@
//
#import <UIKit/UIkit.h>
-#import "ObjGit.h"
+#import "Git.h"
@interface ProjectDetailViewController : UITableViewController {
- ObjGit *detailItem;
+ GITRepo *detailItem;
}
-@property (nonatomic, retain) ObjGit *detailItem;
+@property (nonatomic, retain) GITRepo *detailItem;
@end
View
12 ProjectDetailViewController.m → Classes/ProjectDetailViewController.m
@@ -5,7 +5,7 @@
#import "ProjectDetailViewController.h"
#import "CommitsViewController.h"
-#import "ObjGit.h"
+#import "Git.h"
@implementation ProjectDetailViewController
@@ -19,7 +19,7 @@ - (void)viewWillAppear:(BOOL)animated {
// Scroll the table view to the top before it appears
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointZero animated:NO];
- self.title = [detailItem gitName];
+ self.title = [detailItem desc];
}
// Standard table view data source and delegate methods
@@ -40,7 +40,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
break;
case 1:
// For the branches section, there is size
- rows = [[detailItem getAllRefs] count];
+ rows = [[detailItem branches] count];
break;
default:
break;
@@ -63,10 +63,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
switch (indexPath.section) {
case 0:
- cellText = [detailItem gitName];
+ cellText = [detailItem desc];
break;
case 1:
- cellText = [[[detailItem getAllRefs] objectAtIndex:indexPath.row] objectAtIndex:0];
+ cellText = [[[detailItem branches] objectAtIndex:indexPath.row] objectAtIndex:0];
break;
default:
@@ -100,7 +100,7 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CommitsViewController *commitsViewController = [[CommitsViewController alloc] initWithStyle:UITableViewStylePlain];
- NSArray *refArray = [[detailItem getAllRefs] objectAtIndex:indexPath.row];
+ NSArray *refArray = [[detailItem branches] objectAtIndex:indexPath.row];
NSLog(@"refs:%@", refArray);
commitsViewController.gitRepo = detailItem;
View
1  ProjectViewController.h → Classes/ProjectViewController.h
@@ -5,6 +5,7 @@
#import <UIKit/UIKit.h>
#import "ProjectController.h"
+#import "Git.h"
@interface ProjectViewController : UITableViewController {
ProjectController *projectController;
View
6 ProjectViewController.m → Classes/ProjectViewController.m
@@ -5,8 +5,6 @@
#import "ProjectViewController.h"
#import "ProjectDetailViewController.h"
-#import "ObjGit.h"
-
@implementation ProjectViewController
@@ -40,8 +38,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}
// Get the object to display and set the value in the cell
- ObjGit *itemAtIndex = [projectController objectInListAtIndex:indexPath.row];
- cell.text = [itemAtIndex gitName];
+ GITRepo *itemAtIndex = [projectController objectInListAtIndex:indexPath.row];
+ cell.text = [itemAtIndex desc];
return cell;
}
View
0  ServerViewController.h → Classes/ServerViewController.h
File renamed without changes
View
0  ServerViewController.m → Classes/ServerViewController.m
File renamed without changes
View
28 Client/ASIAuthenticationDialog.h
@@ -0,0 +1,28 @@
+//
+// ASIAuthenticationDialog.h
+// iPhone
+//
+// Created by Ben Copsey on 21/08/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+@class ASIHTTPRequest;
+
+typedef enum _ASIAuthenticationType {
+ ASIStandardAuthenticationType = 0,
+ ASIProxyAuthenticationType = 1
+} ASIAuthenticationType;
+
+@interface ASIAuthenticationDialog : NSObject <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
+ ASIHTTPRequest *request;
+ UIActionSheet *loginDialog;
+ ASIAuthenticationType type;
+}
++ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
++ (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
+
+@property (retain) ASIHTTPRequest *request;
+@property (retain) UIActionSheet *loginDialog;
+@property (assign) ASIAuthenticationType type;
+@end
View
236 Client/ASIAuthenticationDialog.m
@@ -0,0 +1,236 @@
+//
+// ASIAuthenticationDialog.m
+// iPhone
+//
+// Created by Ben Copsey on 21/08/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIAuthenticationDialog.h"
+#import "ASIHTTPRequest.h"
+
+ASIAuthenticationDialog *sharedDialog = nil;
+NSLock *dialogLock = nil;
+
+@interface ASIAuthenticationDialog ()
+- (void)show;
+@end
+
+@implementation ASIAuthenticationDialog
+
++ (void)initialize
+{
+ if (self == [ASIAuthenticationDialog class]) {
+ dialogLock = [[NSLock alloc] init];
+ }
+}
+
++ (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request
+{
+ [dialogLock lock];
+ [sharedDialog release];
+ sharedDialog = [[self alloc] init];
+ [sharedDialog setRequest:request];
+ [sharedDialog setType:ASIProxyAuthenticationType];
+ [sharedDialog show];
+ [dialogLock unlock];
+}
+
++ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request
+{
+ [dialogLock lock];
+ [sharedDialog release];
+ sharedDialog = [[self alloc] init];
+ [sharedDialog setRequest:request];
+ [sharedDialog show];
+ [dialogLock unlock];
+
+}
+
+- (void)show
+{
+ // Create an action sheet to show the login dialog
+ [self setLoginDialog:[[[UIActionSheet alloc] init] autorelease]];
+ [[self loginDialog] setActionSheetStyle:UIActionSheetStyleBlackOpaque];
+ [[self loginDialog] setDelegate:self];
+
+ // We show the login form in a table view, similar to Safari's authentication dialog
+ UITableView *table = [[[UITableView alloc] initWithFrame:CGRectMake(0,80,320,480) style:UITableViewStyleGrouped] autorelease];
+ [table setDelegate:self];
+ [table setDataSource:self];
+ [[self loginDialog] addSubview:table];
+ [[self loginDialog] showInView:[[[UIApplication sharedApplication] windows] objectAtIndex:0]];
+ [[self loginDialog] setFrame:CGRectMake(0,0,320,480)];
+
+ // Setup the title (Couldn't figure out how to put this in the same toolbar as the buttons)
+ UIToolbar *titleBar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,30)] autorelease];
+ UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(10,0,300,30)] autorelease];
+ if ([self type] == ASIProxyAuthenticationType) {
+ [label setText:@"Login to this secure proxy server."];
+ } else {
+ [label setText:@"Login to this secure server."];
+ }
+ [label setTextColor:[UIColor blackColor]];
+ [label setFont:[UIFont systemFontOfSize:13.0]];
+ [label setShadowColor:[UIColor colorWithRed:1 green:1 blue:1 alpha:0.5]];
+ [label setShadowOffset:CGSizeMake(0, 1.0)];
+ [label setOpaque:NO];
+ [label setBackgroundColor:nil];
+ [label setTextAlignment:UITextAlignmentCenter];
+
+ [titleBar addSubview:label];
+ [[self loginDialog] addSubview:titleBar];
+
+ // Setup the toolbar
+ UIToolbar *toolbar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,30,320,50)] autorelease];
+
+ NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];
+ UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease];
+ [items addObject:backButton];
+
+ label = [[[UILabel alloc] initWithFrame:CGRectMake(0,0,170,50)] autorelease];
+ if ([self type] == ASIProxyAuthenticationType) {
+ [label setText:[[self request] proxyHost]];
+ } else {
+ [label setText:[[[self request] url] host]];
+ }
+ [label setTextColor:[UIColor whiteColor]];
+ [label setFont:[UIFont boldSystemFontOfSize:22.0]];
+ [label setShadowColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]];
+ [label setShadowOffset:CGSizeMake(0, -1.0)];
+ [label setOpaque:NO];
+ [label setBackgroundColor:nil];
+ [label setTextAlignment:UITextAlignmentCenter];
+
+ [toolbar addSubview:label];
+
+ UIBarButtonItem *labelButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:nil action:nil] autorelease];
+ [labelButton setCustomView:label];
+ [items addObject:labelButton];
+ [items addObject:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
+ [toolbar setItems:items];
+
+ [[self loginDialog] addSubview:toolbar];
+
+ // Force reload the table content, and focus the first field to show the keyboard
+ [table reloadData];
+ [[[[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] becomeFirstResponder];
+
+}
+
+- (void)cancelAuthenticationFromDialog:(id)sender
+{
+ [[self request] cancelAuthentication];
+ [[self loginDialog] dismissWithClickedButtonIndex:0 animated:YES];
+}
+
+- (void)loginWithCredentialsFromDialog:(id)sender
+{
+ NSString *username = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] text];
+ NSString *password = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] subviews] objectAtIndex:2] text];
+
+ if ([self type] == ASIProxyAuthenticationType) {
+ [[self request] setProxyUsername:username];
+ [[self request] setProxyPassword:password];
+ } else {
+ [[self request] setUsername:username];
+ [[self request] setPassword:password];
+ }
+
+ // Handle NTLM domains
+ NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
+ if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
+ NSString *domain = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]] subviews] objectAtIndex:2] text];
+ if ([self type] == ASIProxyAuthenticationType) {
+ [[self request] setProxyDomain:domain];
+ } else {
+ [[self request] setDomain:domain];
+ }
+ }
+
+ [[self loginDialog] dismissWithClickedButtonIndex:1 animated:YES];
+ [[self request] retryUsingSuppliedCredentials];
+}
+
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
+ if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
+ return 3;
+ }
+ return 2;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
+{
+ if (section == [self numberOfSectionsInTableView:tableView]-1) {
+ return 30;
+ }
+ return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
+{
+ if (section == 0) {
+ 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] initWithFrame:CGRectZero reuseIdentifier:nil] autorelease];
+#else
+ UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
+#endif
+
+ [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+ UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(20,12,260,25)] autorelease];
+ [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+ if ([indexPath section] == 0) {
+ [textField setPlaceholder:@"User"];
+ } else if ([indexPath section] == 1) {
+ [textField setPlaceholder:@"Password"];
+ [textField setSecureTextEntry:YES];
+ } else if ([indexPath section] == 2) {
+ [textField setPlaceholder:@"Domain"];
+ }
+ [cell addSubview:textField];
+
+ return cell;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ return 1;
+}
+
+
+- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
+{
+ if (section == [self numberOfSectionsInTableView:tableView]-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;
+}
+
+@synthesize request;
+@synthesize loginDialog;
+@synthesize type;
+@end
View
61 Client/ASIFormDataRequest.h
@@ -0,0 +1,61 @@
+//
+// ASIFormDataRequest.h
+// asi-http-request
+//
+// 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 {
+
+ // Parameters that will be POSTed to the url
+ NSMutableDictionary *postData;
+
+ // Files that will be POSTed to the url
+ NSMutableDictionary *fileData;
+
+ ASIPostFormat postFormat;
+
+ NSStringEncoding stringEncoding;
+
+#if ASIHTTPREQUEST_DEBUG
+ // 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)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
+
+// Add the contents of a local file to the request
+- (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)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
300 Client/ASIFormDataRequest.m
@@ -0,0 +1,300 @@
+//
+// ASIFormDataRequest.m
+// asi-http-request
+//
+// 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) NSMutableDictionary *postData;
+@property (retain) NSMutableDictionary *fileData;
+
+#if ASIHTTPREQUEST_DEBUG
+- (void)addToDebugBody:(NSString *)string;
+@property (retain, nonatomic) NSString *debugBodyString;
+#endif
+
+@end
+
+@implementation ASIFormDataRequest
+
+#pragma mark utilities
+- (NSString*)encodeURL:(NSString *)string
+{
+ NSString *newString = [(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 ASIHTTPREQUEST_DEBUG
+ [debugBodyString release];
+#endif
+
+ [postData release];
+ [fileData release];
+ [super dealloc];
+}
+
+#pragma mark setup request
+
+- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
+{
+ if (![self postData]) {
+ [self setPostData:[NSMutableDictionary dictionary]];
+ }
+ [[self postData] setValue:[value description] forKey:key];
+ [self setRequestMethod:@"POST"];
+}
+
+- (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
+{
+ if (![self fileData]) {
+ [self setFileData:[NSMutableDictionary dictionary]];
+ }
+
+ // 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 (currently only on Mac OS)
+ // Will return 'application/octet-stream' on iPhone, or if the mime type cannot be determined
+ if (!contentType) {
+ contentType = [ASIHTTPRequest mimeTypeForFileAtPath:data];
+ }
+ }
+
+ NSDictionary *fileInfo = [NSDictionary dictionaryWithObjectsAndKeys:data, @"data", contentType, @"contentType", fileName, @"fileName", nil];
+ [[self fileData] setObject:fileInfo forKey:key];
+ [self setRequestMethod: @"POST"];
+}
+
+- (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
+{
+ if (![self fileData]) {
+ [self setFileData:[NSMutableDictionary dictionary]];
+ }
+ if (!contentType) {
+ contentType = @"application/octet-stream";
+ }
+
+ NSDictionary *fileInfo = [NSDictionary dictionaryWithObjectsAndKeys:data, @"data", contentType, @"contentType", fileName, @"fileName", nil];
+ [[self fileData] setObject:fileInfo forKey:key];
+ [self setRequestMethod: @"POST"];
+}
+
+- (void)buildPostBody
+{
+ if ([self haveBuiltPostBody]) {
+ return;
+ }
+
+#if ASIHTTPREQUEST_DEBUG
+ [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 ASIHTTPREQUEST_DEBUG
+ NSLog(@"%@",[self debugBodyString]);
+ [self setDebugBodyString:nil];
+#endif
+}
+
+
+- (void)buildMultipartFormDataPostBody
+{
+#if ASIHTTPREQUEST_DEBUG
+ [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];
+ NSEnumerator *e = [[self postData] keyEnumerator];
+ NSString *key;
+ NSUInteger i=0;
+ while (key = [e nextObject]) {
+ [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key]];
+ [self appendPostString:[[self postData] objectForKey:key]];
+ 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
+ e = [fileData keyEnumerator];
+ i=0;
+ while (key = [e nextObject]) {
+ NSDictionary *fileInfo = [[self fileData] objectForKey:key];
+ id file = [fileInfo objectForKey:@"data"];
+ NSString *contentType = [fileInfo objectForKey:@"contentType"];
+ NSString *fileName = [fileInfo objectForKey:@"fileName"];
+
+ [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", key, fileName]];
+ [self appendPostString:[NSString stringWithFormat:@"Content-Type: %@; charset=%@\r\n\r\n", contentType, charset]];
+
+ if ([file isKindOfClass:[NSString class]]) {
+ [self appendPostDataFromFile:file];
+ } else {
+ [self appendPostData:file];
+ }
+ 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 ASIHTTPREQUEST_DEBUG
+ [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 ASIHTTPREQUEST_DEBUG
+ [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]];
+
+
+ NSEnumerator *e = [[self postData] keyEnumerator];
+ NSString *key;
+ int i=0;
+ int count = [[self postData] count]-1;
+ while (key = [e nextObject]) {
+ NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:key], [self encodeURL:[[self postData] objectForKey:key]],(i<count ? @"&" : @"")];
+ [self appendPostString:data];
+ i++;
+ }
+#if ASIHTTPREQUEST_DEBUG
+ [self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
+#endif
+}
+
+- (void)appendPostString:(NSString *)string
+{
+#if ASIHTTPREQUEST_DEBUG
+ [self addToDebugBody:string];
+#endif
+ [super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
+}
+
+#if ASIHTTPREQUEST_DEBUG
+- (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 file 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
+
+@synthesize postData;
+@synthesize fileData;
+@synthesize postFormat;
+@synthesize stringEncoding;
+#if ASIHTTPREQUEST_DEBUG
+@synthesize debugBodyString;
+#endif
+@end
View
654 Client/ASIHTTPRequest.h
@@ -0,0 +1,654 @@
+//
+// ASIHTTPRequest.h
+//
+// Created by Ben Copsey on 04/10/2007.
+// Copyright 2007-2009 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"
+
+
+// Make targeting 2.2.1 more reliable
+// See: http://www.blumtnwerx.com/blog/2009/06/cross-sdk-code-hygiene-in-xcode/
+#ifndef __IPHONE_3_0
+ #define __IPHONE_3_0 30000
+#endif
+
+
+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 {
+
+ // The url for this operation, should include GET params in the query string where appropriate
+ NSURL *url;
+
+ // The delegate, you need to manage setting and talking to your delegate in your subclasses
+ id delegate;
+
+ // A queue delegate that should *ALSO* be notified of delegate message (used by ASINetworkQueue)
+ id 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 useCookiePersistance is true, network requests will present valid cookies from previous requests
+ BOOL useCookiePersistance;
+
+ // If useKeychainPersistance 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 useKeychainPersistance;
+
+ // If useSessionPersistance is true, network requests will save credentials and reuse for the duration of the session (until clearSession is called)
+ BOOL useSessionPersistance;
+
+ // 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 uploadProgressDelegate;
+
+ // Delegate for displaying download progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
+ id 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;
+ CFReadStreamRef readStream;
+
+ // Used for authentication
+ CFHTTPAuthenticationRef requestAuthentication;
+ NSMutableDictionary *requestCredentials;
+
+ // Used during NTLM authentication
+ int authenticationRetryCount;
+
+ // Authentication scheme (Basic, Digest, NTLM)
+ NSString *authenticationScheme;
+
+ // Realm for authentication when credentials are required
+ NSString *authenticationRealm;
+
+ // And now, the same thing, but for authenticating proxies
+ BOOL needsProxyAuthentication;
+
+ // 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;
+ NSMutableDictionary *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;
+
+ 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 will block the request until the delegate supplies authentication info
+ NSConditionLock *authenticationLock;
+
+ // This lock prevents the operation from being cancelled at an inopportune moment
+ NSRecursiveLock *cancelledLock;
+
+ // Called on the delegate when the request starts
+ SEL didStartSelector;
+
+ // Called on the delegate when the request completes successfully
+ SEL didFinishSelector;
+
+ // Called on the delegate when the request fails
+ SEL didFailSelector;
+
+ // 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 shouldResetProgressIndicators;
+
+ // 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 cerficates 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;
+
+ // 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;
+
+ // True when request is attempting to handle an authentication challenge
+ BOOL authenticationChallengeInProgress;
+
+ // 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 explictly asked for them
+ // This only affects credentials stored in the session cache when useSessionPersistance is YES. Credentials from the keychain are never presented unless the server asks for them
+ // Default is YES
+ BOOL shouldPresentCredentialsBeforeChallenge;
+}
+
+#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;
+
+#pragma mark setup request
+
+// Add a custom header to the request
+- (void)addRequestHeader:(NSString *)header value:(NSString *)value;
+
+// 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 asynchronously by adding it to the global queue
+// (Use [request start] for a synchronous request)
+- (void)startAsynchronous;
+
+#pragma mark request logic
+
+// Main request loop is in here
+- (void)loadRequest;
+
+// Start the read stream. Called by loadRequest, and again to restart the request when authentication is needed
+- (void)startRequest;
+
+// 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
+
+- (void)updateProgressIndicators;
+- (void)resetUploadProgress:(unsigned long long)value;
+- (void)updateUploadProgress;
+- (void)resetDownloadProgress:(unsigned long long)value;
+- (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;
+
+// Helper method for interacting with progress indicators to abstract the details of different APIS (NSProgressIndicator and UIProgressView)
++ (void)setProgress:(double)progress forProgressIndicator:(id)indicator;
+
+#pragma mark handling request complete / failure
+
+// Called when a request starts, lets the delegate now via didStartSelector
+- (void)requestStarted;
+
+// Called when a request completes successfully, lets the delegate now via didFinishSelector
+- (void)requestFinished;
+
+// Called when a request fails, and lets the delegate now via didFailSelector
+- (void)failWithError:(NSError *)theError;
+
+#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
+// Returns true if the request needs a username and password (or if those supplied were incorrect)
+- (BOOL)readResponseHeadersReturningAuthenticationFailure;
+
+#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 global queue
+
++ (NSOperationQueue *)sharedRequestQueue;
+
+#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
+
+// Only works on Mac OS, will always return 'application/octet-stream' on iPhone
++ (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;
+
+// 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
+
+// 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 miscellany
+
+// Determines whether we're on iPhone OS 2.0 at runtime, currently used to determine whether we should apply a workaround for an issue with converting longs to doubles on iPhone OS 2
++ (BOOL)isiPhoneOS2;
+
+// Used for generating Authorization header when using basic authentication when shouldPresentCredentialsBeforeChallenge is true
+// And also by ASIS3Request
++ (NSString *)base64forData:(NSData *)theData;
+
+#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,setter=setURL:) NSURL *url;
+@property (assign) id delegate;
+@property (assign) id queue;
+@property (assign) id uploadProgressDelegate;
+@property (assign) id downloadProgressDelegate;
+@property (assign) BOOL useKeychainPersistance;
+@property (assign) BOOL useSessionPersistance;
+@property (retain) NSString *downloadDestinationPath;
+@property (retain) NSString *temporaryFileDownloadPath;
+@property (assign) SEL didStartSelector;
+@property (assign) SEL didFinishSelector;
+@property (assign) SEL didFailSelector;
+@property (retain,readonly) NSString *authenticationRealm;
+@property (retain,readonly) NSString *proxyAuthenticationRealm;
+@property (retain) NSError *error;
+@property (assign,readonly) BOOL complete;
+@property (retain,readonly) NSDictionary *responseHeaders;
+@property (retain) NSMutableDictionary *requestHeaders;
+@property (retain) NSMutableArray *requestCookies;
+@property (retain,readonly) NSArray *responseCookies;
+@property (assign) BOOL useCookiePersistance;
+@property (retain) NSDictionary *requestCredentials;
+@property (retain) NSDictionary *proxyCredentials;
+@property (assign,readonly) int responseStatusCode;
+@property (retain,readonly) NSString *responseStatusMessage;
+@property (retain,readonly) 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 shouldResetProgressIndicators;
+@property (retain) 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;
+@property (assign) BOOL didCreateTemporaryPostDataFile;
+@property (assign) BOOL useHTTPVersionOne;
+@property (assign, readonly) unsigned long long partialDownloadSize;
+@property (assign) BOOL shouldRedirect;
+@property (assign) BOOL validatesSecureCertificate;
+@property (assign) BOOL shouldCompressRequestBody;
+@property (assign) BOOL needsProxyAuthentication;
+@property (retain) NSURL *PACurl;
+@property (retain) NSString *authenticationScheme;
+@property (retain) NSString *proxyAuthenticationScheme;
+@property (assign) BOOL shouldPresentAuthenticationDialog;
+@property (assign) BOOL shouldPresentProxyAuthenticationDialog;
+@property (assign) BOOL authenticationChallengeInProgress;
+@property (assign) BOOL shouldPresentCredentialsBeforeChallenge;
+@property (assign, readonly) int authenticationRetryCount;
+@property (assign, readonly) int proxyAuthenticationRetryCount;
+@property (assign) BOOL haveBuiltRequestHeaders;
+@property (assign, nonatomic) BOOL haveBuiltPostBody;
+@end
View
3,236 Client/ASIHTTPRequest.m
3,236 additions, 0 deletions not shown
View
29 Client/ASIHTTPRequestConfig.h
@@ -0,0 +1,29 @@
+//
+// ASIHTTPRequestConfig.h
+// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
+//
+// Created by Ben Copsey on 14/12/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+
+
+/*
+ASIHTTPRequest uses Apple's Reachability class (http://developer.apple.com/iphone/library/samplecode/Reachability/) to turn bandwidth throttling on and off automatically when shouldThrottleBandwidthForWWAN is set to YES on iPhone OS
+
+There are two versions of Apple's Reachability class, both of which are included in the source distribution of ASIHTTPRequest in the External/Reachability folder.
+
+ * Version 2.0 is the latest version. You should use this if you are targeting iPhone OS 3.x and later
+ To use Version 2.0, set this to 1, and include Reachbility.h + Reachbility.m from the Reachability 2.0 folder in your project
+
+ * Version 1.5 is the old version, but it is compatible with both iPhone OS 2.2.1 and iPhone OS 3.0 and later. You should use this if your application needs to work on iPhone OS 2.2.1.
+ To use Version 1.5, set this to 0, and include Reachbility.h + Reachbility.m from the Reachability 1.5 folder in your project
+
+This config option is not used for apps targeting Mac OS X
+*/
+
+#define REACHABILITY_20_API 0
+
+
+// When set to 1, requests will print debug information to the console (currently only used by ASIFormDataRequest)
+#define ASIHTTPREQUEST_DEBUG 1
View
22 Client/ASIInputStream.h
@@ -0,0 +1,22 @@
+//
+// ASIInputStream.h
+// asi-http-request
+//
+// Created by Ben Copsey on 10/08/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+// This is a wrapper for NSInputStream that pretends to be an NSInputStream itself
+// Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead.
+// It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading
+
+@interface ASIInputStream : NSObject {
+ NSInputStream *stream;
+}
++ (id)inputStreamWithFileAtPath:(NSString *)path;
++ (id)inputStreamWithData:(NSData *)data;
+
+@property (retain) NSInputStream *stream;
+@end
View
103 Client/ASIInputStream.m
@@ -0,0 +1,103 @@
+//
+// ASIInputStream.m
+// asi-http-request
+//
+// Created by Ben Copsey on 10/08/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIInputStream.h"
+#import "ASIHTTPRequest.h"
+
+// Used to ensure only one request can read data at once
+static NSLock *readLock = nil;
+
+@implementation ASIInputStream
+
++ (void)initialize
+{
+ if (self == [ASIInputStream class]) {
+ readLock = [[NSLock alloc] init];
+ }
+}
+
++ (id)inputStreamWithFileAtPath:(NSString *)path
+{
+ ASIInputStream *stream = [[[self alloc] init] autorelease];
+ [stream setStream:[NSInputStream inputStreamWithFileAtPath:path]];
+ return stream;
+}
+
++ (id)inputStreamWithData:(NSData *)data
+{
+ ASIInputStream *stream = [[[self alloc] init] autorelease];
+ [stream setStream:[NSInputStream inputStreamWithData:data]];
+ return stream;
+}
+
+- (void)dealloc
+{
+ [stream release];
+ [super dealloc];
+}
+
+
+// Ok, so this works, but I don't really understand why.
+// Ideally, we'd just return the stream's hasBytesAvailable, but CFNetwork seems to want to monopolise our run loop until (presumably) its buffer is full, which will cause timeouts if we're throttling the bandwidth
+// We return NO when we shouldn't be uploading any more data because our bandwidth limit has run out (for now)
+// The call to maxUploadReadLength will recognise that we've run out of our allotted bandwidth limit, and sleep this thread for the rest of the measurement period
+// This method will be called again, but we'll almost certainly return YES the next time around, because we'll have more limit to use up
+// The NO returns seem to snap CFNetwork out of its reverie, and return control to the main loop in loadRequest, so that we can manage timeouts and progress delegate updates
+- (BOOL)hasBytesAvailable
+{
+
+ if ([ASIHTTPRequest isBandwidthThrottled]) {
+ [readLock lock];
+ if ([ASIHTTPRequest maxUploadReadLength] == 0) {
+ [readLock unlock];
+ return NO;
+ }
+ [readLock unlock];
+ }
+ return [[self stream] hasBytesAvailable];
+
+}
+
+// Called when CFNetwork wants to read more of our request body
+// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read
+- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
+{
+ [readLock lock];
+ unsigned long toRead = len;
+ if ([ASIHTTPRequest isBandwidthThrottled]) {
+ toRead = [ASIHTTPRequest maxUploadReadLength];
+ if (toRead > len) {
+ toRead = len;
+
+ // Hopefully this won't happen because hasBytesAvailable will have returned NO, but just in case - we need to read at least 1 byte, or bad things might happen
+ } else if (toRead == 0) {
+ toRead = 1;
+ }
+ //NSLog(@"Throttled read %u",toRead);
+ } else {
+ //NSLog(@"Unthrottled read %u",toRead);
+ }
+ [ASIHTTPRequest incrementBandwidthUsedInLastSecond:toRead];
+ [readLock unlock];
+ return [[self stream] read:buffer maxLength:toRead];
+}
+
+// If we get asked to perform a method we don't have (which is almost all of them), we'll just forward the message to our stream
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
+{
+ return [[self stream] methodSignatureForSelector:aSelector];
+}
+
+- (void)forwardInvocation:(NSInvocation *)anInvocation
+{
+ [anInvocation invokeWithTarget:[self stream]];
+}
+
+@synthesize stream;
+@end
View
16 Client/ASINSStringAdditions.h
@@ -0,0 +1,16 @@
+//
+// ASINSStringAdditions.h
+// asi-http-request
+//
+// Created by Ben Copsey on 12/09/2008.
+// Copyright 2008 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSString (CookieValueEncodingAdditions)
+
+- (NSString *)encodedCookieValue;
+- (NSString *)decodedCookieValue;
+
+@end
View
28 Client/ASINSStringAdditions.m
@@ -0,0 +1,28 @@
+//
+// ASINSStringAdditions.m
+// asi-http-request
+//
+// Created by Ben Copsey on 12/09/2008.
+// Copyright 2008 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASINSStringAdditions.h"
+
+@implementation NSString (CookieValueEncodingAdditions)
+
+- (NSString *)decodedCookieValue
+{
+ NSMutableString *s = [NSMutableString stringWithString:[self stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ //Also swap plus signs for spaces
+ [s replaceOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [s length])];
+ return [NSString stringWithString:s];
+}
+
+- (NSString *)encodedCookieValue
+{
+ return [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+}
+
+@end
+
+
View
120 Client/ASINetworkQueue.h
@@ -0,0 +1,120 @@
+//
+// ASINetworkQueue.h
+// asi-http-request
+//
+// Created by Ben Copsey on 07/11/2008.
+// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface ASINetworkQueue : NSOperationQueue {
+
+ // Delegate will get didFail + didFinish messages (if set)
+ id delegate;
+
+ // Will be called when a request starts with the request as the argument
+ SEL requestDidStartSelector;
+
+ // Will be called when a request completes with the request as the argument
+ SEL requestDidFinishSelector;
+
+ // Will be called when a request fails with the request as the argument
+ SEL requestDidFailSelector;
+
+ // Will be called when the queue finishes with the queue as the argument
+ SEL queueDidFinishSelector;
+
+ // Upload progress indicator, probably an NSProgressIndicator or UIProgressView
+ id uploadProgressDelegate;
+
+ // Total amount uploaded so far for all requests in this queue
+ unsigned long long bytesUploadedSoFar;
+
+ // Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
+ unsigned long long totalBytesToUpload;
+
+ // Download progress indicator, probably an NSProgressIndicator or UIProgressView
+ id downloadProgressDelegate;
+
+ // Total amount downloaded so far for all requests in this queue
+ unsigned long long bytesDownloadedSoFar;
+
+ // Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
+ unsigned long long totalBytesToDownload;
+
+ // When YES, the queue will cancel all requests when a request fails. Default is YES
+ BOOL shouldCancelAllRequestsOnFailure;
+
+ //Number of real requests (excludes HEAD requests created to manage showAccurateProgress)
+ int requestsCount;
+
+ // When NO, this request will only update the progress indicator when it completes
+ // When YES, this request will update the progress indicator according to how much data it has recieved so far
+ // When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts
+ // NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes
+ // Set to YES if the size of a requests in the queue varies greatly for much more accurate results
+ // Default for requests in the queue is NO
+ BOOL showAccurateProgress;
+
+ // Storage container for additional queue information.
+ NSDictionary *userInfo;
+}
+
+// Convenience constructor
++ (id)queue;
+
+// Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
+- (void)addHEADOperation:(NSOperation *)operation;
+
+// Called at the start of a request to add on the size of this upload to the total
+- (void)incrementUploadSizeBy:(unsigned long long)bytes;
+
+// Called during a request when data is written to the upload stream to increment the progress indicator
+- (void)incrementUploadProgressBy:(unsigned long long)bytes;
+
+// Called at the start of a request to add on the size of this download to the total
+- (void)incrementDownloadSizeBy:(unsigned long long)bytes;
+
+// Called during a request when data is received to increment the progress indicator
+- (void)incrementDownloadProgressBy:(unsigned long long)bytes;
+
+// Called during a request when authorisation fails to cancel any progress so far
+- (void)decrementUploadProgressBy:(unsigned long long)bytes;
+
+// Called when the first chunk of data is written to the upload buffer
+// We ignore the first part chunk when tracking upload progress, as kCFStreamPropertyHTTPRequestBytesWrittenCount reports the amount of data written to the buffer, not the amount sent
+// This is to workaround the first 128KB of data appearing in an upload progress delegate immediately
+- (void)setUploadBufferSize:(unsigned long long)bytes;
+
+// All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts
+// This method will start the queue
+- (void)go;
+
+// Used on iPhone platform to show / hide the network activity indicator (in the status bar)
+// On mac, you could subclass to do something else
+- (void)updateNetworkActivityIndicator;
+
+// Returns YES if the queue is in progress
+- (BOOL)isNetworkActive;
+
+
+@property (assign,setter=setUploadProgressDelegate:) id uploadProgressDelegate;
+@property (assign,setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
+
+@property (assign) SEL requestDidStartSelector;
+@property (assign) SEL requestDidFinishSelector;
+@property (assign) SEL requestDidFailSelector;
+@property (assign) SEL queueDidFinishSelector;
+@property (assign) BOOL shouldCancelAllRequestsOnFailure;
+@property (assign) id delegate;
+@property (assign) BOOL showAccurateProgress;
+@property (assign, readonly) int requestsCount;
+@property (retain) NSDictionary *userInfo;
+
+@property (assign) unsigned long long bytesUploadedSoFar;
+@property (assign) unsigned long long totalBytesToUpload;
+@property (assign) unsigned long long bytesDownloadedSoFar;
+@property (assign) unsigned long long totalBytesToDownload;
+
+@end
View
349 Client/ASINetworkQueue.m
@@ -0,0 +1,349 @@
+//
+// ASINetworkQueue.m
+// asi-http-request
+//
+// Created by Ben Copsey on 07/11/2008.
+// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASINetworkQueue.h"
+#import "ASIHTTPRequest.h"
+
+// Private stuff
+@interface ASINetworkQueue ()
+ @property (assign) int requestsCount;
+@end
+
+@implementation ASINetworkQueue
+
+- (id)init
+{
+ self = [super init];
+ [self setShouldCancelAllRequestsOnFailure:YES];
+ [self setMaxConcurrentOperationCount:4];
+ [self setSuspended:YES];
+
+ return self;
+}
+
++ (id)queue
+{
+ return [[[self alloc] init] autorelease];
+}
+
+- (void)dealloc
+{
+ //We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
+ for (ASIHTTPRequest *request in [self operations]) {
+ [request setQueue:nil];
+ }
+ [userInfo release];
+ [super dealloc];
+}
+
+- (BOOL)isNetworkActive
+{
+ return ([self requestsCount] > 0 && ![self isSuspended]);
+}
+
+- (void)updateNetworkActivityIndicator
+{
+#if TARGET_OS_IPHONE
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActive]];
+#endif
+}
+
+- (void)setSuspended:(BOOL)suspend
+{
+ [super setSuspended:suspend];
+ [self updateNetworkActivityIndicator];
+}
+
+
+- (void)go
+{
+ if (![self showAccurateProgress]) {
+ if ([self downloadProgressDelegate]) {
+ [self incrementDownloadSizeBy:[self requestsCount]];
+ }
+ if ([self uploadProgressDelegate]) {
+ [self incrementUploadSizeBy:[self requestsCount]];
+ }
+ }
+ [self setSuspended:NO];
+}
+
+- (void)cancelAllOperations
+{
+ [self setRequestsCount:0];
+ [self setBytesUploadedSoFar:0];
+ [self setTotalBytesToUpload:0];
+ [self setBytesDownloadedSoFar:0];
+ [self setTotalBytesToDownload:0];
+ [super cancelAllOperations];
+ [self updateNetworkActivityIndicator];
+}
+
+- (void)setUploadProgressDelegate:(id)newDelegate
+{
+ uploadProgressDelegate = newDelegate;
+
+#if !TARGET_OS_IPHONE
+ // If the uploadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
+ SEL selector = @selector(setMaxValue:);
+ if ([[self uploadProgressDelegate] respondsToSelector:selector]) {
+ double max = 1.0;
+ NSMethodSignature *signature = [[[self uploadProgressDelegate] class] instanceMethodSignatureForSelector:selector];
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+ [invocation setSelector:selector];
+ [invocation setArgument:&max atIndex:2];
+ [invocation invokeWithTarget:[self uploadProgressDelegate]];
+ }
+#endif
+}
+
+
+- (void)setDownloadProgressDelegate:(id)newDelegate
+{
+ downloadProgressDelegate = newDelegate;
+
+#if !TARGET_OS_IPHONE
+ // If the downloadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
+ SEL selector = @selector(setMaxValue:);
+ if ([[self