├── .gitattributes ├── iPhone Sample ├── iphone-icon.png ├── Resources │ ├── client.p12 │ └── info.png ├── iphone-tests-icon.png ├── iPhone_Prefix.pch ├── DetailCell.h ├── RequestProgressCell.h ├── ToggleCell.h ├── InfoCell.h ├── main.m ├── iPhoneSampleAppDelegate.h ├── iPadSampleAppDelegate.h ├── SynchronousViewController.h ├── iPhoneSampleAppDelegate.m ├── AuthenticationViewController.h ├── ToggleCell.m ├── SampleViewController.h ├── UploadViewController.h ├── iPadSampleAppDelegate.m ├── WebPageViewController.h ├── RootViewController.h ├── Tests-Info.plist ├── iPhoneInfo.plist ├── QueueViewController.h ├── DetailCell.m ├── RequestProgressCell.m ├── iPadInfo.plist ├── InfoCell.m ├── SampleViewController.m ├── GHUnitIOSTestMain.m ├── RootViewController.m ├── SynchronousViewController.m └── UploadViewController.m ├── Mac.xcodeproj └── TemplateIcon.icns ├── Mac Sample ├── English.lproj │ └── InfoPlist.strings ├── Mac_Prefix.pch ├── main.m ├── Info.plist ├── Tests-Info.plist └── AppDelegate.h ├── .gitignore ├── Classes ├── Tests │ ├── BlocksTests.h │ ├── ASIDataCompressorTests.h │ ├── ASIWebPageRequestTests.h │ ├── ASICloudFilesRequestTests.h │ ├── ASIDownloadCacheTests.h │ ├── ASITestCase.h │ ├── ASIFormDataRequestTests.h │ ├── ClientCertificateTests.h │ ├── ASIS3RequestTests.h │ ├── ASITestCase.m │ ├── PerformanceTests.h │ ├── ProxyTests.h │ ├── StressTests.h │ ├── ASIWebPageRequestTests.m │ ├── ASIHTTPRequestTests.h │ ├── ASINetworkQueueTests.h │ ├── ClientCertificateTests.m │ ├── GHUnitTestMain.m │ ├── BlocksTests.m │ ├── StressTests.m │ └── ASIDataCompressorTests.m ├── CloudFiles │ ├── ASICloudFilesObject.m │ ├── ASICloudFilesContainer.m │ ├── ASICloudFilesObject.h │ ├── ASICloudFilesContainerXMLParserDelegate.h │ ├── ASICloudFilesContainer.h │ ├── ASICloudFilesRequest.h │ ├── ASICloudFilesContainerRequest.h │ ├── ASICloudFilesCDNRequest.h │ ├── ASICloudFilesContainerXMLParserDelegate.m │ ├── ASICloudFilesObjectRequest.h │ ├── ASICloudFilesRequest.m │ ├── ASICloudFilesContainerRequest.m │ └── ASICloudFilesCDNRequest.m ├── S3 │ ├── ASIS3Bucket.m │ ├── ASIS3ServiceRequest.h │ ├── ASINSXMLParserCompat.h │ ├── ASIS3Bucket.h │ ├── ASIS3BucketObject.h │ ├── ASIS3BucketObject.m │ ├── ASIS3BucketRequest.h │ ├── ASIS3ServiceRequest.m │ ├── ASIS3ObjectRequest.h │ ├── ASIS3Request.h │ ├── ASIS3ObjectRequest.m │ └── ASIS3BucketRequest.m ├── ASIInputStream.h ├── ASIAuthenticationDialog.h ├── ASIHTTPRequestConfig.h ├── ASIHTTPRequestDelegate.h ├── ASIProgressDelegate.h ├── ASIDataDecompressor.h ├── ASIDataCompressor.h ├── ASIDownloadCache.h ├── ASIFormDataRequest.h ├── ASIInputStream.m ├── ASIWebPageRequest │ └── ASIWebPageRequest.h ├── ASINetworkQueue.h ├── ASICacheDelegate.h ├── ASIDataDecompressor.m └── ASIDataCompressor.m ├── External └── GHUnit │ └── README-GHUnit ├── Build Scripts ├── set_version_number.rb ├── fetch_ios_ghunit.rb └── fetch_mac_ghunit.rb ├── strict.xcconfig ├── LICENSE ├── DONORS └── README.textile /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -crlf -diff -merge 2 | -------------------------------------------------------------------------------- /iPhone Sample/iphone-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/iPhone Sample/iphone-icon.png -------------------------------------------------------------------------------- /Mac.xcodeproj/TemplateIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/Mac.xcodeproj/TemplateIcon.icns -------------------------------------------------------------------------------- /iPhone Sample/Resources/client.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/iPhone Sample/Resources/client.p12 -------------------------------------------------------------------------------- /iPhone Sample/Resources/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/iPhone Sample/Resources/info.png -------------------------------------------------------------------------------- /iPhone Sample/iphone-tests-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/iPhone Sample/iphone-tests-icon.png -------------------------------------------------------------------------------- /Mac Sample/English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamma/asi-http-request/master/Mac Sample/English.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /Mac Sample/Mac_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Mac OS Sample Application' target in the 'asi-http-request' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *xcodeproj/*mode* 3 | *xcodeproj/*pbxuser 4 | *xcodeproj/*per* 5 | *xcodeproj/project.xcworkspace 6 | *xcodeproj/xcuserdata 7 | *tmproj 8 | .DS_Store 9 | profile 10 | *.pbxuser 11 | *.mode1v3 12 | External/GHUnit/* 13 | .svn -------------------------------------------------------------------------------- /Classes/Tests/BlocksTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlocksTests.h 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 18/10/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | 12 | @interface BlocksTests : ASITestCase { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /iPhone Sample/iPhone_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'iPhone' target in the 'iPhone' project 3 | // 4 | 5 | // See: https://devforums.apple.com/thread/66169?start=25&tstart=0 6 | #import 7 | 8 | #ifdef __OBJC__ 9 | #import 10 | #import 11 | #endif 12 | -------------------------------------------------------------------------------- /Mac Sample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // Mac-Os-Sample-main.m 3 | // asi-http-request 4 | // 5 | // Created by Ben Copsey on 09/07/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **) argv); 14 | } 15 | -------------------------------------------------------------------------------- /Classes/Tests/ASIDataCompressorTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressorTests.h 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | 12 | @interface ASIDataCompressorTests : ASITestCase { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/Tests/ASIWebPageRequestTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIWebPageRequestTests.h 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 06/01/2011. 6 | // Copyright 2011 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | 12 | @interface ASIWebPageRequestTests : ASITestCase { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /External/GHUnit/README-GHUnit: -------------------------------------------------------------------------------- 1 | This folder is where ASIHTTPRequest looks for GHUnit frameworks. 2 | 3 | When you run one of the test targets, a build script will attempt to download a pre-compiled framework and install it here, if one does not already exist. If you would prefer to build GHUnit yourself, simply grab a copy from https://github.com/gabriel/gh-unit, and drop your built framework in this folder. -------------------------------------------------------------------------------- /Classes/Tests/ASICloudFilesRequestTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesRequestTests.h 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASITestCase.h" 8 | 9 | @class ASINetworkQueue; 10 | 11 | @interface ASICloudFilesRequestTests : ASITestCase { 12 | ASINetworkQueue *networkQueue; 13 | float progress; 14 | } 15 | 16 | @property (retain,nonatomic) ASINetworkQueue *networkQueue; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /iPhone Sample/DetailCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailCell.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 16/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface DetailCell : UITableViewCell { 13 | 14 | } 15 | + (id)cell; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /iPhone Sample/RequestProgressCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // RequestProgressCell.h 3 | // iPhone 4 | // 5 | // Created by Ben Copsey on 03/10/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface RequestProgressCell : UITableViewCell { 13 | UIProgressView *progressView; 14 | } 15 | + (id)cell; 16 | 17 | @property (retain, nonatomic) UIProgressView *progressView; 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/Tests/ASIDownloadCacheTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDownloadCacheTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 03/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | 12 | @interface ASIDownloadCacheTests : ASITestCase { 13 | NSUInteger requestsFinishedCount; 14 | BOOL requestRedirectedWasCalled; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /iPhone Sample/ToggleCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ToggleCell.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ToggleCell : UITableViewCell { 13 | UISwitch *toggle; 14 | } 15 | + (id)cell; 16 | 17 | @property (assign, nonatomic) UISwitch *toggle; 18 | @end 19 | -------------------------------------------------------------------------------- /iPhone Sample/InfoCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // InfoCell.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface InfoCell : UITableViewCell { 13 | 14 | } 15 | + (id)cell; 16 | + (NSUInteger)neededHeightForDescription:(NSString *)description withTableWidth:(NSUInteger)tableWidth; 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/Tests/ASITestCase.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASITestCase.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 26/07/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #if TARGET_OS_IPHONE 12 | #import 13 | #else 14 | #import 15 | #endif 16 | 17 | @interface ASITestCase : GHTestCase { 18 | } 19 | - (NSString *)filePathForTemporaryTestFiles; 20 | @end 21 | -------------------------------------------------------------------------------- /iPhone Sample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 22/03/2009. 6 | // Copyright All-Seeing Interactive 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 13 | int retVal = UIApplicationMain(argc, argv, nil, nil); 14 | [pool release]; 15 | return retVal; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Classes/Tests/ASIFormDataRequestTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIFormDataRequestTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 08/11/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | @interface ASIFormDataRequestTests : ASITestCase { 12 | float progress; 13 | } 14 | 15 | - (void)testPostWithFileUpload; 16 | - (void)testEmptyData; 17 | - (void)testSubclass; 18 | - (void)testURLEncodedPost; 19 | - (void)testCharset; 20 | - (void)testPUT; 21 | - (void)testCopy; 22 | @end 23 | -------------------------------------------------------------------------------- /iPhone Sample/iPhoneSampleAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // iPhoneSampleAppDelegate.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright All-Seeing Interactive 2008. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iPhoneSampleAppDelegate : NSObject { 12 | IBOutlet UIWindow *window; 13 | IBOutlet UITabBarController *tabBarController; 14 | } 15 | 16 | @property (nonatomic, retain) UIWindow *window; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesObject.m 3 | // 4 | // Created by Michael Mayo on 1/7/10. 5 | // 6 | 7 | #import "ASICloudFilesObject.h" 8 | 9 | 10 | @implementation ASICloudFilesObject 11 | 12 | @synthesize name, hash, bytes, contentType, lastModified, data, metadata; 13 | 14 | + (id)object { 15 | ASICloudFilesObject *object = [[[self alloc] init] autorelease]; 16 | return object; 17 | } 18 | 19 | -(void)dealloc { 20 | [name release]; 21 | [hash release]; 22 | [contentType release]; 23 | [lastModified release]; 24 | [data release]; 25 | [metadata release]; 26 | [super dealloc]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainer.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainer.m 3 | // 4 | // Created by Michael Mayo on 1/7/10. 5 | // 6 | 7 | #import "ASICloudFilesContainer.h" 8 | 9 | 10 | @implementation ASICloudFilesContainer 11 | 12 | // regular container attributes 13 | @synthesize name, count, bytes; 14 | 15 | // CDN container attributes 16 | @synthesize cdnEnabled, ttl, cdnURL, logRetention, referrerACL, useragentACL; 17 | 18 | + (id)container { 19 | ASICloudFilesContainer *container = [[[self alloc] init] autorelease]; 20 | return container; 21 | } 22 | 23 | -(void) dealloc { 24 | [name release]; 25 | [super dealloc]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /iPhone Sample/iPadSampleAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // iPadSampleAppDelegate.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 15/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iPadSampleAppDelegate : NSObject { 12 | UIWindow *window; 13 | UISplitViewController *splitViewController; 14 | } 15 | 16 | @property (nonatomic, retain) IBOutlet UIWindow *window; 17 | @property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /iPhone Sample/SynchronousViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SynchronousViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SampleViewController.h" 11 | @class ASIHTTPRequest; 12 | 13 | @interface SynchronousViewController : SampleViewController { 14 | ASIHTTPRequest *request; 15 | UITextField *urlField; 16 | UITextView *responseField; 17 | UIButton *goButton; 18 | 19 | } 20 | - (IBAction)simpleURLFetch:(id)sender; 21 | 22 | @property (retain, nonatomic) ASIHTTPRequest *request; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /iPhone Sample/iPhoneSampleAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // iPhoneSampleAppDelegate.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright All-Seeing Interactive 2008. All rights reserved. 7 | // 8 | 9 | #import "iPhoneSampleAppDelegate.h" 10 | 11 | @implementation iPhoneSampleAppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(UIApplication *)application 14 | { 15 | [[tabBarController view] setFrame:CGRectMake(0, 0, 320, 480)]; 16 | [window addSubview:[tabBarController view]]; 17 | } 18 | 19 | - (void)dealloc 20 | { 21 | [window release]; 22 | [super dealloc]; 23 | } 24 | 25 | @synthesize window; 26 | 27 | @end 28 | 29 | -------------------------------------------------------------------------------- /Classes/Tests/ClientCertificateTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClientCertificateTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 18/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | // Currently, these tests only work on iOS - it looks like the method for parsing the PKCS12 file would need to be ported 10 | 11 | #import 12 | #import 13 | #import "ASITestCase.h" 14 | 15 | @interface ClientCertificateTests : ASITestCase { 16 | 17 | } 18 | - (void)testClientCertificate; 19 | + (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /iPhone Sample/AuthenticationViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AuthenticationViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 01/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SampleViewController.h" 11 | @class ASIHTTPRequest; 12 | 13 | @interface AuthenticationViewController : SampleViewController { 14 | 15 | ASIHTTPRequest *request; 16 | 17 | UISwitch *useKeychain; 18 | UISwitch *useBuiltInDialog; 19 | UITextView *responseField; 20 | } 21 | - (IBAction)fetchTopSecretInformation:(id)sender; 22 | 23 | @property (retain, nonatomic) ASIHTTPRequest *request; 24 | @end 25 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesObject.h 3 | // 4 | // Created by Michael Mayo on 1/7/10. 5 | // 6 | 7 | #import 8 | 9 | 10 | @interface ASICloudFilesObject : NSObject { 11 | NSString *name; 12 | NSString *hash; 13 | NSUInteger bytes; 14 | NSString *contentType; 15 | NSDate *lastModified; 16 | NSData *data; 17 | NSMutableDictionary *metadata; 18 | } 19 | 20 | @property (retain) NSString *name; 21 | @property (retain) NSString *hash; 22 | @property (assign) NSUInteger bytes; 23 | @property (retain) NSString *contentType; 24 | @property (retain) NSDate *lastModified; 25 | @property (retain) NSData *data; 26 | @property (retain) NSMutableDictionary *metadata; 27 | 28 | + (id)object; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Classes/Tests/ASIS3RequestTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3RequestTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 12/07/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | @class ASINetworkQueue; 12 | 13 | @interface ASIS3RequestTests : ASITestCase { 14 | ASINetworkQueue *networkQueue; 15 | float progress; 16 | } 17 | 18 | - (void)testAuthenticationHeaderGeneration; 19 | - (void)testREST; 20 | - (void)testFailure; 21 | - (void)testListRequest; 22 | - (void)testSubclasses; 23 | - (void)createTestBucket; 24 | - (void)testCopy; 25 | - (void)testHTTPS; 26 | 27 | @property (retain,nonatomic) ASINetworkQueue *networkQueue; 28 | @end 29 | -------------------------------------------------------------------------------- /iPhone Sample/ToggleCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ToggleCell.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ToggleCell.h" 10 | 11 | 12 | @implementation ToggleCell 13 | 14 | + (id)cell 15 | { 16 | ToggleCell *cell = [[[ToggleCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"ToggleCell"] autorelease]; 17 | [[cell textLabel] setTextAlignment:UITextAlignmentLeft]; 18 | [cell setToggle:[[[UISwitch alloc] initWithFrame:CGRectMake(0,0,20,20)] autorelease]]; 19 | [cell setAccessoryView:[cell toggle]]; 20 | return cell; 21 | } 22 | 23 | @synthesize toggle; 24 | @end 25 | -------------------------------------------------------------------------------- /iPhone Sample/SampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SampleViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface SampleViewController : UIViewController { 13 | UINavigationBar *navigationBar; 14 | UITableView *tableView; 15 | } 16 | 17 | - (void)showNavigationButton:(UIBarButtonItem *)button; 18 | - (void)hideNavigationButton:(UIBarButtonItem *)button; 19 | 20 | @property (retain, nonatomic) IBOutlet UINavigationBar *navigationBar; 21 | @property (retain, nonatomic) IBOutlet UITableView *tableView; 22 | @end 23 | -------------------------------------------------------------------------------- /iPhone Sample/UploadViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UploadViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 31/12/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SampleViewController.h" 11 | @class ASIFormDataRequest; 12 | 13 | @interface UploadViewController : SampleViewController { 14 | 15 | ASIFormDataRequest *request; 16 | 17 | IBOutlet UIProgressView *progressIndicator; 18 | UITextView *resultView; 19 | } 20 | 21 | - (IBAction)performLargeUpload:(id)sender; 22 | - (IBAction)toggleThrottling:(id)sender; 23 | 24 | @property (retain, nonatomic) ASIFormDataRequest *request; 25 | @end 26 | -------------------------------------------------------------------------------- /iPhone Sample/iPadSampleAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // iPadSampleAppDelegate.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 15/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "iPadSampleAppDelegate.h" 10 | 11 | @implementation iPadSampleAppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(UIApplication *)application 14 | { 15 | [window addSubview:[splitViewController view]]; 16 | [window makeKeyAndVisible]; 17 | } 18 | 19 | - (void)dealloc { 20 | [splitViewController release]; 21 | [window release]; 22 | [super dealloc]; 23 | } 24 | 25 | 26 | @synthesize window; 27 | @synthesize splitViewController; 28 | @end 29 | -------------------------------------------------------------------------------- /iPhone Sample/WebPageViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebPageViewController.h 3 | // iPhone 4 | // 5 | // Created by Ben Copsey on 03/10/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SampleViewController.h" 11 | 12 | @class ASIWebPageRequest; 13 | 14 | @interface WebPageViewController : SampleViewController { 15 | UIWebView *webView; 16 | UITextField *urlField; 17 | UITextView *responseField; 18 | UISwitch *replaceURLsSwitch; 19 | ASIWebPageRequest *request; 20 | NSMutableArray *requestsInProgress; 21 | } 22 | - (void)fetchURL:(NSURL *)url; 23 | 24 | @property (retain, nonatomic) ASIWebPageRequest *request; 25 | @property (retain, nonatomic) NSMutableArray *requestsInProgress; 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/Tests/ASITestCase.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASITestCase.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 26/07/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | 12 | @implementation ASITestCase 13 | 14 | - (NSString *)filePathForTemporaryTestFiles 15 | { 16 | NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequest Test Files"]; 17 | if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:NULL]) { 18 | [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:NULL]; 19 | } 20 | return path; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /iPhone Sample/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 16/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RootViewController : UITableViewController { 12 | UISplitViewController *splitViewController; 13 | UIPopoverController *popoverController; 14 | UIBarButtonItem *rootPopoverButtonItem; 15 | } 16 | @property (nonatomic, assign) IBOutlet UISplitViewController *splitViewController; 17 | @property (nonatomic, retain) UIPopoverController *popoverController; 18 | @property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem; 19 | @end 20 | -------------------------------------------------------------------------------- /Classes/Tests/PerformanceTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/12/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | 12 | @interface PerformanceTests : ASITestCase { 13 | NSURL *testURL; 14 | 15 | NSDate *testStartDate; 16 | int requestsComplete; 17 | NSMutableArray *responseData; 18 | unsigned long bytesDownloaded; 19 | } 20 | 21 | - (void)testASIHTTPRequestAsyncPerformance; 22 | - (void)testNSURLConnectionAsyncPerformance; 23 | 24 | @property (retain,nonatomic) NSURL *testURL; 25 | @property (retain,nonatomic) NSDate *testStartDate; 26 | @property (assign,nonatomic) int requestsComplete; 27 | @property (retain,nonatomic) NSMutableArray *responseData; 28 | @end 29 | -------------------------------------------------------------------------------- /Build Scripts/set_version_number.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This script sets a version number for ASIHTTPRequest based on the last commit, and is run when you build one of the targets in the Xcode projects that come with ASIHTTPRequest 4 | # It only really needs to run on my computer, not on yours... :) 5 | require 'find' 6 | if (File.exists?('.git') && File.directory?('.git') && File.exists?('/usr/local/bin/git')) 7 | newversion = `/usr/local/bin/git describe --tags`.match(/(v([0-9]+)(\.([0-9]+)){1,}-([0-9]+))/).to_s.gsub(/[0-9]+$/){|commit| (commit.to_i + 1).to_s}+Time.now.strftime(" %Y-%m-%d") 8 | buffer = File.new('Classes/ASIHTTPRequest.m','r').read 9 | if !buffer.match(/#{Regexp.quote(newversion)}/) 10 | buffer = buffer.sub(/(NSString \*ASIHTTPRequestVersion = @\")(.*)(";)/,'\1'+newversion+'\3'); 11 | File.open('Classes/ASIHTTPRequest.m','w') {|fw| fw.write(buffer)} 12 | end 13 | end -------------------------------------------------------------------------------- /Classes/Tests/ProxyTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProxyTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 02/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | @class ASINetworkQueue; 12 | 13 | // Proxy tests must be run separately from other tests, using the proxy you specify 14 | // Some tests require an authenticating proxy to function 15 | 16 | @interface ProxyTests : ASITestCase { 17 | ASINetworkQueue *queue; 18 | BOOL complete; 19 | } 20 | - (void)testProxy; 21 | - (void)testProxyAutodetect; 22 | - (void)testProxyWithSuppliedAuthenticationCredentials; 23 | - (void)testDoubleAuthentication; 24 | - (void)testProxyForHTTPS; 25 | 26 | @property (retain) ASINetworkQueue *queue; 27 | @property (assign) BOOL complete; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /iPhone Sample/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ASIHTTPRequestTests 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | iphone-tests-icon.png 13 | CFBundleIdentifier 14 | com.allseeinginteractive.asihttprequest.tests 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | 24 | 25 | -------------------------------------------------------------------------------- /strict.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // strict.xcconfig 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 25/11/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES 10 | GCC_WARN_SHADOW = YES 11 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 12 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES 13 | GCC_WARN_ABOUT_RETURN_TYPE = YES 14 | //GCC_WARN_MISSING_PARENTHESES = YES 15 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES 16 | //GCC_WARN_ABOUT_MISSING_NEWLINE = YES 17 | GCC_WARN_SIGN_COMPARE = YES 18 | GCC_WARN_STRICT_SELECTOR_MATCH = missing value 19 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES 20 | GCC_WARN_UNDECLARED_SELECTOR = YES 21 | GCC_WARN_UNUSED_FUNCTION = YES 22 | GCC_WARN_UNUSED_LABEL = YES 23 | GCC_WARN_UNUSED_VALUE = YES 24 | GCC_WARN_UNUSED_VARIABLE = YES 25 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 26 | //RUN_CLANG_STATIC_ANALYZER = YES -------------------------------------------------------------------------------- /Classes/S3/ASIS3Bucket.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3Bucket.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIS3Bucket.h" 10 | 11 | 12 | @implementation ASIS3Bucket 13 | 14 | + (id)bucketWithOwnerID:(NSString *)anOwnerID ownerName:(NSString *)anOwnerName 15 | { 16 | ASIS3Bucket *bucket = [[[self alloc] init] autorelease]; 17 | [bucket setOwnerID:anOwnerID]; 18 | [bucket setOwnerName:anOwnerName]; 19 | return bucket; 20 | } 21 | 22 | - (NSString *)description 23 | { 24 | return [NSString stringWithFormat:@"Name: %@ creationDate: %@ ownerID: %@ ownerName: %@",[self name],[self creationDate],[self ownerID],[self ownerName]]; 25 | } 26 | 27 | 28 | @synthesize name; 29 | @synthesize creationDate; 30 | @synthesize ownerID; 31 | @synthesize ownerName; 32 | @end 33 | -------------------------------------------------------------------------------- /Build Scripts/fetch_ios_ghunit.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This script fetches a pre-compiled copy of the iOS GHUnit.framework, if one isn't already in the External/GHUnit folder 4 | # This replaces the old system, where GHUnit was included as a git submodule, because: 5 | # a) git submodules confuse people (including me) 6 | # b) GHUnit seems to be tricky to build without warnings 7 | # The pre-compiled frameworks on allseeing-i.com were taken directly from those on the GHUnit downloads page on GitHub 8 | # If you'd rather build GHUnit yourself, simply grab a copy from http://github.com/gabriel/gh-unit and drop your built framework into External/GHUnit 9 | 10 | require 'net/http' 11 | if (!File.exists?('External/GHUnit/GHUnitIOS.framework')) 12 | `curl -s http://allseeing-i.com/ASIHTTPRequest/GHUnit/GHUnit-IOS.zip > External/GHUnit/GHUnit-IOS.zip` 13 | `unzip External/GHUnit/GHUnit-IOS.zip -d External/GHUnit/ & rm External/GHUnit/GHUnit-IOS.zip` 14 | end -------------------------------------------------------------------------------- /Build Scripts/fetch_mac_ghunit.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This script fetches a pre-compiled copy of the Mac GHUnit.framework, if one isn't already in the External/GHUnit folder 4 | # This replaces the old system, where GHUnit was included as a git submodule, because: 5 | # a) git submodules confuse people (including me) 6 | # b) GHUnit seems to be tricky to build without warnings 7 | # The pre-compiled frameworks on allseeing-i.com were taken directly from those on the GHUnit downloads page on GitHub 8 | # If you'd rather build GHUnit yourself, simply grab a copy from http://github.com/gabriel/gh-unit and drop your built framework into External/GHUnit 9 | 10 | require 'net/http' 11 | if (!File.exists?('External/GHUnit/GHUnit.framework')) 12 | `curl -s http://allseeing-i.com/ASIHTTPRequest/GHUnit/GHUnit-Mac.zip > External/GHUnit/GHUnit-Mac.zip` 13 | `unzip External/GHUnit/GHUnit-Mac.zip -d External/GHUnit/ & rm External/GHUnit/GHUnit-Mac.zip` 14 | end -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainerXMLParserDelegate.h 3 | // 4 | // Created by Michael Mayo on 1/10/10. 5 | // 6 | 7 | #import "ASICloudFilesRequest.h" 8 | 9 | #if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) 10 | #import "ASINSXMLParserCompat.h" 11 | #endif 12 | 13 | @class ASICloudFilesContainer; 14 | 15 | @interface ASICloudFilesContainerXMLParserDelegate : NSObject { 16 | 17 | NSMutableArray *containerObjects; 18 | 19 | // Internally used while parsing the response 20 | NSString *currentContent; 21 | NSString *currentElement; 22 | ASICloudFilesContainer *currentObject; 23 | } 24 | 25 | @property (retain) NSMutableArray *containerObjects; 26 | 27 | @property (retain) NSString *currentElement; 28 | @property (retain) NSString *currentContent; 29 | @property (retain) ASICloudFilesContainer *currentObject; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3ServiceRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3ServiceRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Create an ASIS3ServiceRequest to obtain a list of your buckets 9 | 10 | #import 11 | #import "ASIS3Request.h" 12 | 13 | @class ASIS3Bucket; 14 | 15 | @interface ASIS3ServiceRequest : ASIS3Request { 16 | 17 | // Internally used while parsing the response 18 | ASIS3Bucket *currentBucket; 19 | NSString *ownerName; 20 | NSString *ownerID; 21 | 22 | // A list of the buckets stored on S3 for this account 23 | NSMutableArray *buckets; 24 | } 25 | 26 | // Perform a GET request on the S3 service 27 | // This will fetch a list of the buckets attached to the S3 account 28 | + (id)serviceRequest; 29 | 30 | @property (retain, readonly) NSMutableArray *buckets; 31 | @end 32 | -------------------------------------------------------------------------------- /iPhone Sample/iPhoneInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ASIHTTPRequest Demo 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | iphone-icon.png 13 | CFBundleIdentifier 14 | com.allseeinginteractive.asihttprequest.iphone.sample 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | NSMainNibFile 24 | iPhoneMainWindow 25 | 26 | 27 | -------------------------------------------------------------------------------- /Classes/S3/ASINSXMLParserCompat.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASINSXMLParserCompat.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // This file exists to prevent warnings about the NSXMLParserDelegate protocol when building S3 or Cloud Files stuff 5 | // 6 | // Created by Ben Copsey on 17/06/2010. 7 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 8 | // 9 | 10 | 11 | #if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0) 12 | @protocol NSXMLParserDelegate 13 | 14 | @optional 15 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict; 16 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName; 17 | 18 | @end 19 | #endif 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /iPhone Sample/QueueViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QueueViewController.h 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SampleViewController.h" 11 | 12 | @class ASINetworkQueue; 13 | 14 | @interface QueueViewController : SampleViewController { 15 | ASINetworkQueue *networkQueue; 16 | 17 | UIImageView *imageView1; 18 | UIImageView *imageView2; 19 | UIImageView *imageView3; 20 | UIProgressView *progressIndicator; 21 | UISwitch *accurateProgress; 22 | UIProgressView *imageProgressIndicator1; 23 | UIProgressView *imageProgressIndicator2; 24 | UIProgressView *imageProgressIndicator3; 25 | UILabel *imageLabel1; 26 | UILabel *imageLabel2; 27 | UILabel *imageLabel3; 28 | BOOL failed; 29 | 30 | } 31 | 32 | - (IBAction)fetchThreeImages:(id)sender; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainer.h 3 | // 4 | // Created by Michael Mayo on 1/7/10. 5 | // 6 | 7 | #import 8 | 9 | 10 | @interface ASICloudFilesContainer : NSObject { 11 | 12 | // regular container attributes 13 | NSString *name; 14 | NSUInteger count; 15 | NSUInteger bytes; 16 | 17 | // CDN container attributes 18 | BOOL cdnEnabled; 19 | NSUInteger ttl; 20 | NSString *cdnURL; 21 | BOOL logRetention; 22 | NSString *referrerACL; 23 | NSString *useragentACL; 24 | } 25 | 26 | + (id)container; 27 | 28 | // regular container attributes 29 | @property (retain) NSString *name; 30 | @property (assign) NSUInteger count; 31 | @property (assign) NSUInteger bytes; 32 | 33 | // CDN container attributes 34 | @property (assign) BOOL cdnEnabled; 35 | @property (assign) NSUInteger ttl; 36 | @property (retain) NSString *cdnURL; 37 | @property (assign) BOOL logRetention; 38 | @property (retain) NSString *referrerACL; 39 | @property (retain) NSString *useragentACL; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Mac Sample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.allseeing-i.asi-http-request 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | NSMainNibFile 24 | MainMenu 25 | NSPrincipalClass 26 | NSApplication 27 | CFBundleDisplayName 28 | ASIHTTPRequest Demo 29 | 30 | 31 | -------------------------------------------------------------------------------- /Mac Sample/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.allseeing-i.asi-http-request 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | NSMainNibFile 24 | MainMenu 25 | NSPrincipalClass 26 | NSApplication 27 | CFBundleDisplayName 28 | ASIHTTPRequest Unit Tests 29 | 30 | 31 | -------------------------------------------------------------------------------- /iPhone Sample/DetailCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailCell.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 16/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "DetailCell.h" 10 | 11 | 12 | @implementation DetailCell 13 | 14 | + (id)cell 15 | { 16 | DetailCell *cell = [[[DetailCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:@"HeaderCell"] autorelease]; 17 | [[cell detailTextLabel] setTextAlignment:UITextAlignmentLeft]; 18 | [[cell detailTextLabel] setFont:[UIFont systemFontOfSize:14]]; 19 | return cell; 20 | } 21 | 22 | - (void)layoutSubviews 23 | { 24 | [super layoutSubviews]; 25 | int tablePadding = 40; 26 | int tableWidth = [[self superview] frame].size.width; 27 | if (tableWidth > 480) { // iPad 28 | tablePadding = 110; 29 | } 30 | [[self textLabel] setFrame:CGRectMake(5,5,120,20)]; 31 | [[self detailTextLabel] setFrame:CGRectMake(135,5,[self frame].size.width-145-tablePadding,20)]; 32 | 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Classes/ASIInputStream.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIInputStream.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 10/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ASIHTTPRequest; 12 | 13 | // This is a wrapper for NSInputStream that pretends to be an NSInputStream itself 14 | // Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead. 15 | // It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading 16 | 17 | @interface ASIInputStream : NSObject { 18 | NSInputStream *stream; 19 | ASIHTTPRequest *request; 20 | } 21 | + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request; 22 | + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request; 23 | 24 | @property (retain, nonatomic) NSInputStream *stream; 25 | @property (assign, nonatomic) ASIHTTPRequest *request; 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3Bucket.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3Bucket.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Instances of this class represent buckets stored on S3 9 | // ASIS3ServiceRequests return an array of ASIS3Buckets when you perform a service GET query 10 | // You'll probably never need to create instances of ASIS3Bucket yourself 11 | 12 | #import 13 | 14 | 15 | @interface ASIS3Bucket : NSObject { 16 | 17 | // The name of this bucket (will be unique throughout S3) 18 | NSString *name; 19 | 20 | // The date this bucket was created 21 | NSDate *creationDate; 22 | 23 | // Information about the owner of this bucket 24 | NSString *ownerID; 25 | NSString *ownerName; 26 | } 27 | 28 | + (id)bucketWithOwnerID:(NSString *)ownerID ownerName:(NSString *)ownerName; 29 | 30 | @property (retain) NSString *name; 31 | @property (retain) NSDate *creationDate; 32 | @property (retain) NSString *ownerID; 33 | @property (retain) NSString *ownerName; 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/Tests/StressTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // StressTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 30/10/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASITestCase.h" 11 | 12 | @class ASIHTTPRequest; 13 | 14 | 15 | @interface MyDelegate : NSObject { 16 | ASIHTTPRequest *request; 17 | } 18 | @property (retain) ASIHTTPRequest *request; 19 | @end 20 | 21 | @interface StressTests : ASITestCase { 22 | float progress; 23 | ASIHTTPRequest *cancelRequest; 24 | NSDate *cancelStartDate; 25 | MyDelegate *delegate; 26 | NSLock *createRequestLock; 27 | } 28 | 29 | - (void)testCancelQueue; 30 | 31 | - (void)testCancelStressTest; 32 | - (void)performCancelRequest; 33 | 34 | - (void)testRedirectStressTest; 35 | - (void)performRedirectRequest; 36 | 37 | - (void)testSetDelegate; 38 | - (void)performSetDelegateRequest; 39 | 40 | - (void)setProgress:(float)newProgress; 41 | 42 | @property (retain) ASIHTTPRequest *cancelRequest; 43 | @property (retain) NSDate *cancelStartDate; 44 | @property (retain) MyDelegate *delegate; 45 | @property (retain) NSLock *createRequestLock; 46 | @end 47 | -------------------------------------------------------------------------------- /iPhone Sample/RequestProgressCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // RequestProgressCell.m 3 | // iPhone 4 | // 5 | // Created by Ben Copsey on 03/10/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "RequestProgressCell.h" 10 | 11 | 12 | @implementation RequestProgressCell 13 | 14 | + (id)cell 15 | { 16 | RequestProgressCell *cell = [[[RequestProgressCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"RequestProgressCell"] autorelease]; 17 | [[cell textLabel] setTextAlignment:UITextAlignmentLeft]; 18 | [[cell textLabel] setFont:[UIFont systemFontOfSize:12]]; 19 | [[cell textLabel] setLineBreakMode:UILineBreakModeMiddleTruncation]; 20 | [cell setProgressView:[[[UIProgressView alloc] initWithFrame:CGRectMake(0,0,100,20)] autorelease]]; 21 | [cell setAccessoryView:[cell progressView]]; 22 | return cell; 23 | } 24 | 25 | - (void)dealloc 26 | { 27 | [progressView release]; 28 | [super dealloc]; 29 | } 30 | 31 | - (void)layoutSubviews 32 | { 33 | [super layoutSubviews]; 34 | CGRect f = [[self accessoryView] frame]; 35 | [[self accessoryView] setFrame:CGRectMake(f.origin.x, f.origin.y+6, f.size.width, f.size.height)]; 36 | 37 | } 38 | 39 | @synthesize progressView; 40 | @end 41 | -------------------------------------------------------------------------------- /Classes/ASIAuthenticationDialog.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIAuthenticationDialog.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 21/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @class ASIHTTPRequest; 12 | 13 | typedef enum _ASIAuthenticationType { 14 | ASIStandardAuthenticationType = 0, 15 | ASIProxyAuthenticationType = 1 16 | } ASIAuthenticationType; 17 | 18 | @interface ASIAutorotatingViewController : UIViewController 19 | @end 20 | 21 | @interface ASIAuthenticationDialog : ASIAutorotatingViewController { 22 | ASIHTTPRequest *request; 23 | ASIAuthenticationType type; 24 | UITableView *tableView; 25 | UIViewController *presentingController; 26 | BOOL didEnableRotationNotifications; 27 | } 28 | + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request; 29 | + (void)dismiss; 30 | 31 | @property (retain) ASIHTTPRequest *request; 32 | @property (assign) ASIAuthenticationType type; 33 | @property (assign) BOOL didEnableRotationNotifications; 34 | @property (retain, nonatomic) UIViewController *presentingController; 35 | @end 36 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Michael Mayo on 22/12/09. 6 | // mike.mayo@rackspace.com or mike@overhrd.com 7 | // twitter.com/greenisus 8 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 9 | // 10 | // A class for accessing data stored on the Rackspace Cloud Files Service 11 | // http://www.rackspacecloud.com/cloud_hosting_products/files 12 | // 13 | // Cloud Files Developer Guide: 14 | // http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf 15 | 16 | #import 17 | #import "ASIHTTPRequest.h" 18 | 19 | 20 | @interface ASICloudFilesRequest : ASIHTTPRequest { 21 | } 22 | 23 | + (NSString *)storageURL; 24 | + (NSString *)cdnManagementURL; 25 | + (NSString *)authToken; 26 | 27 | #pragma mark Rackspace Cloud Authentication 28 | 29 | + (id)authenticationRequest; 30 | + (NSError *)authenticate; 31 | + (NSString *)username; 32 | + (void)setUsername:(NSString *)username; 33 | + (NSString *)apiKey; 34 | + (void)setApiKey:(NSString *)apiKey; 35 | 36 | // helper to parse dates in the format returned by Cloud Files 37 | -(NSDate *)dateFromString:(NSString *)dateString; 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /iPhone Sample/iPadInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ASIHTTPRequest Demo 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | iphone-icon.png 13 | CFBundleIdentifier 14 | com.allseeinginteractive.asihttprequest.ipad.sample 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | NSMainNibFile 24 | iPadMainWindow 25 | UISupportedInterfaceOrientations 26 | 27 | UIInterfaceOrientationPortrait 28 | UIInterfaceOrientationPortraitUpsideDown 29 | UIInterfaceOrientationLandscapeLeft 30 | UIInterfaceOrientationLandscapeRight 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Classes/ASIHTTPRequestConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIHTTPRequestConfig.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 14/12/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | 10 | // ====== 11 | // Debug output configuration options 12 | // ====== 13 | 14 | // When set to 1 ASIHTTPRequests will print information about what a request is doing 15 | #ifndef DEBUG_REQUEST_STATUS 16 | #define DEBUG_REQUEST_STATUS 0 17 | #endif 18 | 19 | // When set to 1, ASIFormDataRequests will print information about the request body to the console 20 | #ifndef DEBUG_FORM_DATA_REQUEST 21 | #define DEBUG_FORM_DATA_REQUEST 0 22 | #endif 23 | 24 | // When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console 25 | #ifndef DEBUG_THROTTLING 26 | #define DEBUG_THROTTLING 0 27 | #endif 28 | 29 | // When set to 1, ASIHTTPRequests will print information about persistent connections to the console 30 | #ifndef DEBUG_PERSISTENT_CONNECTIONS 31 | #define DEBUG_PERSISTENT_CONNECTIONS 0 32 | #endif 33 | 34 | // When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console 35 | #ifndef DEBUG_HTTP_AUTHENTICATION 36 | #define DEBUG_HTTP_AUTHENTICATION 0 37 | #endif 38 | -------------------------------------------------------------------------------- /Classes/Tests/ASIWebPageRequestTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIWebPageRequestTests.m 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 06/01/2011. 6 | // Copyright 2011 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIWebPageRequestTests.h" 10 | #import "ASIWebPageRequest.h" 11 | 12 | @implementation ASIWebPageRequestTests 13 | 14 | - (void)testEncoding 15 | { 16 | NSArray *encodings = [NSArray arrayWithObjects:@"us-ascii",@"iso-8859-1",@"utf-16",@"utf-8",nil]; 17 | NSArray *expectedResponses = [NSArray arrayWithObjects:@"Hi there",@"Olá",@"你好",@"今日は",nil]; 18 | NSUInteger i; 19 | for (i=0; i<[encodings count]; i++) { 20 | ASIWebPageRequest *request = [ASIWebPageRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://allseeing-i.com/ASIHTTPRequest/tests/asiwebpagerequest/character-encoding/%@",[encodings objectAtIndex:i]]]]; 21 | [request setUserInfo:[NSDictionary dictionaryWithObject:[expectedResponses objectAtIndex:i] forKey:@"expected-response"]]; 22 | [request setDelegate:self]; 23 | [request setUrlReplacementMode:ASIReplaceExternalResourcesWithLocalURLs]; 24 | [request startAsynchronous]; 25 | } 26 | } 27 | 28 | - (void)requestFinished:(ASIHTTPRequest *)request 29 | { 30 | if ([[request userInfo] objectForKey:@"expected-response"]) { 31 | BOOL success = ([[request responseString] rangeOfString:[[request userInfo] objectForKey:@"expected-response"]].location != NSNotFound); 32 | GHAssertTrue(success,@"Response HTML used wrong encoding"); 33 | } 34 | } 35 | 36 | - (void)requestFailed:(ASIHTTPRequest *)request 37 | { 38 | GHAssertNil([request error],@"Request failed, cannot proceed with test"); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainerRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainerRequest.h 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASICloudFilesRequest.h" 8 | 9 | @class ASICloudFilesContainer, ASICloudFilesContainerXMLParserDelegate; 10 | 11 | @interface ASICloudFilesContainerRequest : ASICloudFilesRequest { 12 | 13 | // Internally used while parsing the response 14 | NSString *currentContent; 15 | NSString *currentElement; 16 | ASICloudFilesContainer *currentObject; 17 | ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate; 18 | } 19 | 20 | @property (retain) NSString *currentElement; 21 | @property (retain) NSString *currentContent; 22 | @property (retain) ASICloudFilesContainer *currentObject; 23 | @property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate; 24 | 25 | // HEAD // 26 | // HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used. 27 | + (id)accountInfoRequest; 28 | - (NSUInteger)containerCount; 29 | - (NSUInteger)bytesUsed; 30 | 31 | // GET /// 32 | // Create a request to list all containers 33 | + (id)listRequest; 34 | + (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker; 35 | - (NSArray *)containers; 36 | 37 | // PUT /// 38 | + (id)createContainerRequest:(NSString *)containerName; 39 | 40 | // DELETE /// 41 | + (id)deleteContainerRequest:(NSString *)containerName; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Classes/ASIHTTPRequestDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIHTTPRequestDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/04/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | @class ASIHTTPRequest; 10 | 11 | @protocol ASIHTTPRequestDelegate 12 | 13 | @optional 14 | 15 | // These are the default delegate methods for request status 16 | // You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector 17 | - (void)requestStarted:(ASIHTTPRequest *)request; 18 | - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders; 19 | - (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL; 20 | - (void)requestFinished:(ASIHTTPRequest *)request; 21 | - (void)requestFailed:(ASIHTTPRequest *)request; 22 | - (void)requestRedirected:(ASIHTTPRequest *)request; 23 | 24 | // When a delegate implements this method, it is expected to process all incoming data itself 25 | // This means that responseData / responseString / downloadDestinationPath etc are ignored 26 | // You can have the request call a different method by setting didReceiveDataSelector 27 | - (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data; 28 | 29 | // If a delegate implements one of these, it will be asked to supply credentials when none are available 30 | // The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set 31 | // or cancel it ([request cancelAuthentication]) 32 | - (void)authenticationNeededForRequest:(ASIHTTPRequest *)request; 33 | - (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3BucketObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3BucketObject.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/07/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Instances of this class represent objects stored in a bucket on S3 9 | // ASIS3BucketRequests return an array of ASIS3BucketObjects when you perform a list query 10 | 11 | #import 12 | @class ASIS3ObjectRequest; 13 | 14 | @interface ASIS3BucketObject : NSObject { 15 | 16 | // The bucket this object belongs to 17 | NSString *bucket; 18 | 19 | // The key (path) of this object in the bucket 20 | NSString *key; 21 | 22 | // When this object was last modified 23 | NSDate *lastModified; 24 | 25 | // The ETag for this object's content 26 | NSString *ETag; 27 | 28 | // The size in bytes of this object 29 | unsigned long long size; 30 | 31 | // Info about the owner 32 | NSString *ownerID; 33 | NSString *ownerName; 34 | } 35 | 36 | + (id)objectWithBucket:(NSString *)bucket; 37 | 38 | // Returns a request that will fetch this object when run 39 | - (ASIS3ObjectRequest *)GETRequest; 40 | 41 | // Returns a request that will replace this object with the contents of the file at filePath when run 42 | - (ASIS3ObjectRequest *)PUTRequestWithFile:(NSString *)filePath; 43 | 44 | // Returns a request that will delete this object when run 45 | - (ASIS3ObjectRequest *)DELETERequest; 46 | 47 | @property (retain) NSString *bucket; 48 | @property (retain) NSString *key; 49 | @property (retain) NSDate *lastModified; 50 | @property (retain) NSString *ETag; 51 | @property (assign) unsigned long long size; 52 | @property (retain) NSString *ownerID; 53 | @property (retain) NSString *ownerName; 54 | @end 55 | -------------------------------------------------------------------------------- /Classes/ASIProgressDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIProgressDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/04/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | @class ASIHTTPRequest; 10 | 11 | @protocol ASIProgressDelegate 12 | 13 | @optional 14 | 15 | // These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X) 16 | // If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead 17 | #if TARGET_OS_IPHONE 18 | - (void)setProgress:(float)newProgress; 19 | #else 20 | - (void)setDoubleValue:(double)newProgress; 21 | - (void)setMaxValue:(double)newMax; 22 | #endif 23 | 24 | // Called when the request receives some data - bytes is the length of that data 25 | - (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes; 26 | 27 | // Called when the request sends some data 28 | // The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API 29 | // bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again) 30 | - (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes; 31 | 32 | // Called when a request needs to change the length of the content to download 33 | - (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength; 34 | 35 | // Called when a request needs to change the length of the content to upload 36 | // newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking 37 | - (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength; 38 | @end 39 | -------------------------------------------------------------------------------- /Classes/ASIDataDecompressor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataDecompressor.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | // This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk 10 | // You may also find it helpful if you need to inflate data and files yourself - see the class methods below 11 | // Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net 12 | 13 | #import 14 | #import 15 | 16 | @interface ASIDataDecompressor : NSObject { 17 | BOOL streamReady; 18 | z_stream zStream; 19 | } 20 | 21 | // Convenience constructor will call setupStream for you 22 | + (id)decompressor; 23 | 24 | // Uncompress the passed chunk of data 25 | - (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err; 26 | 27 | // Convenience method - pass it some deflated data, and you'll get inflated data back 28 | + (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err; 29 | 30 | // Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath 31 | + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err; 32 | 33 | // Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor' 34 | - (NSError *)setupStream; 35 | 36 | // Tells zlib to clean up. You need to call this if you need to cancel inflating part way through 37 | // If inflating finishes or fails, this method will be called automatically 38 | - (NSError *)closeStream; 39 | 40 | @property (assign, readonly) BOOL streamReady; 41 | @end 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | * Copyright (c) 2007-2011, All-Seeing Interactive 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the All-Seeing Interactive nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY All-Seeing Interactive ''AS IS'' AND ANY 16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL All-Seeing Interactive BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | A different license may apply to other software included in this package, 27 | including GHUnit and Andrew Donoho's Reachability class. Please consult their 28 | respective headers for the terms of their individual licenses. -------------------------------------------------------------------------------- /DONORS: -------------------------------------------------------------------------------- 1 | ASIHTTPRequest donors 2 | 3 | I am very grateful to the following people for their generous donations: 4 | 5 | Marcelo Alves (@xfer) 6 | AzroTech, Inc (http://azrotech.com) 7 | Karl Beck 8 | John Brayton 9 | Stephan Burlot (http://www.coriolis.ch) 10 | Jack Cardinal (http://www.intomotion.com) 11 | Wonki Chung 12 | Matt Coneybeare (http://urbanapps.com) 13 | Connected Bits LLC (http://www.connectedbits.com) 14 | Robert Davis 15 | Julian Dreissig (http://dreissig.net) 16 | Ernandes Mourao Jr. (http://www.mstocksapp.com) 17 | Felis de Brito 18 | Sam DeVore (http://scidsolutions.com) 19 | Nathan de Vries (http://www.atnan.com) 20 | @fpillet (www.commandfusion.com) 21 | Matthew Frederick 22 | Ole Gammelgaard (http://www.trickclown.dk) 23 | Ganasa LLC 24 | Leo Giertz (http://barefoothackers.se) 25 | James Hartzell 26 | Hunter Hillegas 27 | Marcus Hobbs 28 | Felix Holmgren 29 | Cesar Jacquet 30 | Philip Jespersen 31 | Jaanus Kase 32 | Thomas Kiesl (http://kiesl.eu) 33 | Aviel Lazar 34 | Maksim Libenson 35 | John Paul May (http://smhk.com) 36 | Rosario Milone (http://vgmtorrents.net) 37 | Austin Murkland 38 | Jirapong Nanta (http://bananacoding.com) 39 | Ben Pettit (http://http://digimulti.com) 40 | George Photakis 41 | Dominik Pich (http://pich.info) 42 | Spencer Pieters (http://www.appwizard.be) 43 | Peter Pistorius (http://appfactory.co.za) 44 | Shawn Roske 45 | Collin Ruffenach 46 | Alessandro Segala (http://letsdev.it) 47 | Ben Scheirman 48 | Basil Shkara (http://www.oiledmachine.com) 49 | Greg Short (http://crystalpix.com) 50 | Jacob Sologub (http://irompler.com) 51 | Jakub Suder (http://psionides.jogger.pl) 52 | Kyle Van Essen 53 | Rowan Willson 54 | Dan Zeitman 55 | 56 | Many thanks! 57 | 58 | Doesn’t this list look awfully short without your name on it? 59 | If you'd like to donate, go here: http://pledgie.com/campaigns/11463 60 | 61 | -------------------------------------------------------------------------------- /Classes/Tests/ASIHTTPRequestTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIHTTPRequestTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/08/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | @class ASIHTTPRequest; 12 | 13 | @interface ASIHTTPRequestTests : ASITestCase { 14 | float progress; 15 | BOOL started; 16 | BOOL finished; 17 | BOOL failed; 18 | BOOL receivedResponseHeaders; 19 | NSMutableData *responseData; 20 | } 21 | 22 | - (void)testBasicDownload; 23 | - (void)testBase64Encode; 24 | - (void)testDelegateMethods; 25 | - (void)testConditionalGET; 26 | - (void)testException; 27 | - (void)testTimeOut; 28 | - (void)testRequestMethod; 29 | - (void)testHTTPVersion; 30 | - (void)testUserAgent; 31 | - (void)testAutomaticRedirection; 32 | - (void)test30xCrash; 33 | - (void)testUploadContentLength; 34 | - (void)testDownloadContentLength; 35 | - (void)testFileDownload; 36 | - (void)testDownloadProgress; 37 | - (void)testUploadProgress; 38 | - (void)testCookies; 39 | - (void)testRemoveCredentialsFromKeychain; 40 | - (void)testBasicAuthentication; 41 | - (void)testDigestAuthentication; 42 | - (void)testNTLMHandshake; 43 | - (void)testCharacterEncoding; 44 | - (void)testCompressedResponse; 45 | - (void)testCompressedResponseDownloadToFile; 46 | - (void)test000SSL; 47 | - (void)testRedirectPreservesSession; 48 | - (void)testTooMuchRedirection; 49 | - (void)testRedirectToNewDomain; 50 | - (void)test303Redirect; 51 | - (void)testSubclass; 52 | - (void)testTimeOutWithoutDownloadDelegate; 53 | - (void)testThrottlingDownloadBandwidth; 54 | - (void)testThrottlingUploadBandwidth; 55 | #if TARGET_OS_IPHONE 56 | - (void)testReachability; 57 | #endif 58 | - (void)testAutomaticRetry; 59 | - (void)testCloseConnection; 60 | - (void)testPersistentConnections; 61 | - (void)testNilPortCredentialsMatching; 62 | 63 | @property (retain, nonatomic) NSMutableData *responseData; 64 | @end 65 | -------------------------------------------------------------------------------- /Classes/ASIDataCompressor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressor.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | // This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk 10 | // You may also find it helpful if you need to deflate data and files yourself - see the class methods below 11 | // Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net 12 | 13 | #import 14 | #import 15 | 16 | @interface ASIDataCompressor : NSObject { 17 | BOOL streamReady; 18 | z_stream zStream; 19 | } 20 | 21 | // Convenience constructor will call setupStream for you 22 | + (id)compressor; 23 | 24 | // Compress the passed chunk of data 25 | // Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data 26 | - (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish; 27 | 28 | // Convenience method - pass it some data, and you'll get deflated data back 29 | + (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err; 30 | 31 | // Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath 32 | + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err; 33 | 34 | // Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor' 35 | - (NSError *)setupStream; 36 | 37 | // Tells zlib to clean up. You need to call this if you need to cancel deflating part way through 38 | // If deflating finishes or fails, this method will be called automatically 39 | - (NSError *)closeStream; 40 | 41 | @property (assign, readonly) BOOL streamReady; 42 | @end 43 | -------------------------------------------------------------------------------- /Classes/ASIDownloadCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDownloadCache.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASICacheDelegate.h" 11 | 12 | @interface ASIDownloadCache : NSObject { 13 | 14 | // The default cache policy for this cache 15 | // Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy 16 | // Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy 17 | ASICachePolicy defaultCachePolicy; 18 | 19 | // The directory in which cached data will be stored 20 | // Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory 21 | NSString *storagePath; 22 | 23 | // Mediates access to the cache 24 | NSRecursiveLock *accessLock; 25 | 26 | // When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them 27 | BOOL shouldRespectCacheControlHeaders; 28 | } 29 | 30 | // Returns a static instance of an ASIDownloadCache 31 | // In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache 32 | // To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]]; 33 | + (id)sharedCache; 34 | 35 | // A helper function that determines if the server has requested data should not be cached by looking at the request's response headers 36 | + (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request; 37 | 38 | // A list of file extensions that we know won't be readable by a webview when accessed locally 39 | // If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html' 40 | + (NSArray *)fileExtensionsToHandleAsHTML; 41 | 42 | @property (assign, nonatomic) ASICachePolicy defaultCachePolicy; 43 | @property (retain, nonatomic) NSString *storagePath; 44 | @property (retain) NSRecursiveLock *accessLock; 45 | @property (assign) BOOL shouldRespectCacheControlHeaders; 46 | @end 47 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesCDNRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesCDNRequest.h 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASICloudFilesRequest.h" 8 | 9 | @class ASICloudFilesContainerXMLParserDelegate; 10 | 11 | @interface ASICloudFilesCDNRequest : ASICloudFilesRequest { 12 | NSString *accountName; 13 | NSString *containerName; 14 | ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate; 15 | 16 | } 17 | 18 | @property (retain) NSString *accountName; 19 | @property (retain) NSString *containerName; 20 | @property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate; 21 | 22 | 23 | // HEAD /// 24 | // Response: 25 | // X-CDN-Enabled: True 26 | // X-CDN-URI: http://cdn.cloudfiles.mosso.com/c1234 27 | // X-CDN-SSL-URI: https://cdn.ssl.cloudfiles.mosso.com/c1234 28 | // X-CDN-TTL: 86400 29 | + (id)containerInfoRequest:(NSString *)containerName; 30 | - (BOOL)cdnEnabled; 31 | - (NSString *)cdnURI; 32 | - (NSString *)cdnSSLURI; 33 | - (NSUInteger)cdnTTL; 34 | 35 | 36 | // GET // 37 | // limit, marker, format, enabled_only=true 38 | + (id)listRequest; 39 | + (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly; 40 | - (NSArray *)containers; 41 | 42 | 43 | // PUT /// 44 | // PUT operations against a Container are used to CDN-enable that Container. 45 | // Include an HTTP header of X-TTL to specify a custom TTL. 46 | + (id)putRequestWithContainer:(NSString *)containerName; 47 | + (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl; 48 | // returns: - (NSString *)cdnURI; 49 | 50 | // POST /// 51 | // POST operations against a CDN-enabled Container are used to adjust CDN attributes. 52 | // The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN. 53 | // X-TTL: 86400 54 | // X-CDN-Enabled: True 55 | + (id)postRequestWithContainer:(NSString *)containerName; 56 | + (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl; 57 | // returns: - (NSString *)cdnURI; 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3BucketObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3BucketObject.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/07/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIS3BucketObject.h" 10 | #import "ASIS3ObjectRequest.h" 11 | 12 | @implementation ASIS3BucketObject 13 | 14 | + (id)objectWithBucket:(NSString *)theBucket 15 | { 16 | ASIS3BucketObject *object = [[[self alloc] init] autorelease]; 17 | [object setBucket:theBucket]; 18 | return object; 19 | } 20 | 21 | - (void)dealloc 22 | { 23 | [bucket release]; 24 | [key release]; 25 | [lastModified release]; 26 | [ETag release]; 27 | [ownerID release]; 28 | [ownerName release]; 29 | [super dealloc]; 30 | } 31 | 32 | - (ASIS3ObjectRequest *)GETRequest 33 | { 34 | return [ASIS3ObjectRequest requestWithBucket:[self bucket] key:[self key]]; 35 | } 36 | 37 | - (ASIS3ObjectRequest *)PUTRequestWithFile:(NSString *)filePath 38 | { 39 | return [ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:[self bucket] key:[self key]]; 40 | } 41 | 42 | - (ASIS3ObjectRequest *)DELETERequest 43 | { 44 | ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:[self bucket] key:[self key]]; 45 | [request setRequestMethod:@"DELETE"]; 46 | return request; 47 | } 48 | 49 | - (NSString *)description 50 | { 51 | return [NSString stringWithFormat:@"Key: %@ lastModified: %@ ETag: %@ size: %llu ownerID: %@ ownerName: %@",[self key],[self lastModified],[self ETag],[self size],[self ownerID],[self ownerName]]; 52 | } 53 | 54 | - (id)copyWithZone:(NSZone *)zone 55 | { 56 | ASIS3BucketObject *newBucketObject = [[[self class] alloc] init]; 57 | [newBucketObject setBucket:[self bucket]]; 58 | [newBucketObject setKey:[self key]]; 59 | [newBucketObject setLastModified:[self lastModified]]; 60 | [newBucketObject setETag:[self ETag]]; 61 | [newBucketObject setSize:[self size]]; 62 | [newBucketObject setOwnerID:[self ownerID]]; 63 | [newBucketObject setOwnerName:[self ownerName]]; 64 | return newBucketObject; 65 | } 66 | 67 | @synthesize bucket; 68 | @synthesize key; 69 | @synthesize lastModified; 70 | @synthesize ETag; 71 | @synthesize size; 72 | @synthesize ownerID; 73 | @synthesize ownerName; 74 | @end 75 | -------------------------------------------------------------------------------- /iPhone Sample/InfoCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // InfoCell.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "InfoCell.h" 10 | 11 | 12 | @implementation InfoCell 13 | 14 | + (id)cell 15 | { 16 | InfoCell *cell = [[[InfoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"InfoCell"] autorelease]; 17 | if ([[UIScreen mainScreen] bounds].size.width > 480) { // iPad 18 | [[cell textLabel] setFont:[UIFont systemFontOfSize:14]]; 19 | } else { 20 | [[cell textLabel] setFont:[UIFont systemFontOfSize:13]]; 21 | } 22 | [[cell textLabel] setLineBreakMode:UILineBreakModeWordWrap]; 23 | [[cell textLabel] setNumberOfLines:0]; 24 | 25 | if ([[UIScreen mainScreen] bounds].size.width > 480) { // iPad 26 | UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(10,10,48,48)] autorelease]; 27 | [imageView setImage:[UIImage imageNamed:@"info.png"]]; 28 | [[cell contentView] addSubview:imageView]; 29 | } 30 | return cell; 31 | } 32 | 33 | - (void)layoutSubviews 34 | { 35 | [super layoutSubviews]; 36 | int tablePadding = 40; 37 | int tableWidth = [[self superview] frame].size.width; 38 | if (tableWidth > 480) { // iPad 39 | tablePadding = 110; 40 | [[self textLabel] setFrame:CGRectMake(70,10,tableWidth-tablePadding-70,[[self class] neededHeightForDescription:[[self textLabel] text] withTableWidth:tableWidth])]; 41 | } else { 42 | [[self textLabel] setFrame:CGRectMake(10,10,tableWidth-tablePadding,[[self class] neededHeightForDescription:[[self textLabel] text] withTableWidth:tableWidth])]; 43 | } 44 | 45 | } 46 | 47 | + (NSUInteger)neededHeightForDescription:(NSString *)description withTableWidth:(NSUInteger)tableWidth 48 | { 49 | int tablePadding = 40; 50 | int offset = 0; 51 | int textSize = 13; 52 | if (tableWidth > 480) { // iPad 53 | tablePadding = 110; 54 | offset = 70; 55 | textSize = 14; 56 | } 57 | CGSize labelSize = [description sizeWithFont:[UIFont systemFontOfSize:textSize] constrainedToSize:CGSizeMake(tableWidth-tablePadding-offset,1000) lineBreakMode:UILineBreakModeWordWrap]; 58 | if (labelSize.height < 48) { 59 | return 58; 60 | } 61 | return labelSize.height; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Mac Sample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // 4 | // Created by Ben Copsey on 09/07/2008. 5 | // Copyright 2008 All-Seeing Interactive Ltd. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class ASIHTTPRequest; 11 | @class ASINetworkQueue; 12 | 13 | @interface AppDelegate : NSObject { 14 | ASINetworkQueue *networkQueue; 15 | IBOutlet NSProgressIndicator *progressIndicator; 16 | IBOutlet NSTextView *htmlSource; 17 | IBOutlet NSTextField *fileLocation; 18 | IBOutlet NSWindow *window; 19 | IBOutlet NSWindow *loginWindow; 20 | 21 | IBOutlet NSButton *showAccurateProgress; 22 | 23 | IBOutlet NSTextField *host; 24 | IBOutlet NSTextField *realm; 25 | IBOutlet NSTextField *username; 26 | IBOutlet NSTextField *password; 27 | 28 | IBOutlet NSTextField *topSecretInfo; 29 | IBOutlet NSButton *keychainCheckbox; 30 | 31 | IBOutlet NSImageView *imageView1; 32 | IBOutlet NSImageView *imageView2; 33 | IBOutlet NSImageView *imageView3; 34 | IBOutlet NSProgressIndicator *imageProgress1; 35 | IBOutlet NSProgressIndicator *imageProgress2; 36 | IBOutlet NSProgressIndicator *imageProgress3; 37 | 38 | IBOutlet NSButton *startButton; 39 | IBOutlet NSButton *resumeButton; 40 | 41 | IBOutlet NSTextField *bandwidthUsed; 42 | 43 | ASIHTTPRequest *bigFetchRequest; 44 | IBOutlet NSTextField *postStatus; 45 | 46 | IBOutlet NSTableView *tableView; 47 | IBOutlet NSTextField *tableLoadStatus; 48 | NSMutableArray *rowData; 49 | ASINetworkQueue *tableQueue; 50 | 51 | IBOutlet WebView *webView; 52 | IBOutlet NSTextView *webPageSource; 53 | IBOutlet NSTextField *urlField; 54 | IBOutlet NSButton *dataURICheckbox; 55 | } 56 | 57 | - (IBAction)simpleURLFetch:(id)sender; 58 | - (IBAction)URLFetchWithProgress:(id)sender; 59 | - (IBAction)stopURLFetchWithProgress:(id)sender; 60 | - (IBAction)resumeURLFetchWithProgress:(id)sender; 61 | 62 | - (IBAction)fetchThreeImages:(id)sender; 63 | 64 | 65 | - (IBAction)dismissAuthSheet:(id)sender; 66 | - (IBAction)fetchTopSecretInformation:(id)sender; 67 | 68 | - (IBAction)postWithProgress:(id)sender; 69 | 70 | - (IBAction)throttleBandwidth:(id)sender; 71 | 72 | - (IBAction)reloadTableData:(id)sender; 73 | - (IBAction)clearCache:(id)sender; 74 | - (IBAction)fetchWebPage:(id)sender; 75 | 76 | @property (retain, nonatomic) ASIHTTPRequest *bigFetchRequest; 77 | @property (retain, nonatomic) NSMutableArray *rowData; 78 | @property (retain, nonatomic) ASINetworkQueue *tableQueue; 79 | @end 80 | -------------------------------------------------------------------------------- /Classes/Tests/ASINetworkQueueTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASINetworkQueueTests.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 08/11/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASITestCase.h" 10 | 11 | /* 12 | IMPORTANT 13 | Code that appears in these tests is not for general purpose use. 14 | You should not use [networkQueue waitUntilAllOperationsAreFinished] or [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]] in your own software. 15 | They are used here to force a queue to operate synchronously to simplify writing the tests. 16 | IMPORTANT 17 | */ 18 | 19 | @class ASIHTTPRequest; 20 | @class ASINetworkQueue; 21 | 22 | @interface ASINetworkQueueTests : ASITestCase { 23 | ASIHTTPRequest *requestThatShouldFail; 24 | BOOL complete; 25 | BOOL request_didfail; 26 | BOOL request_succeeded; 27 | float progress; 28 | int addedRequests; 29 | 30 | 31 | NSOperationQueue *immediateCancelQueue; 32 | NSMutableArray *failedRequests; 33 | NSMutableArray *finishedRequests; 34 | 35 | ASINetworkQueue *releaseTestQueue; 36 | ASINetworkQueue *cancelQueue; 37 | 38 | int authenticationPromptCount; 39 | 40 | ASINetworkQueue *postQueue; 41 | 42 | ASINetworkQueue *testNTLMQueue; 43 | 44 | ASINetworkQueue *addMoreRequestsQueue; 45 | int requestsFinishedCount; 46 | 47 | BOOL started; 48 | BOOL finished; 49 | BOOL failed; 50 | BOOL headFailed; 51 | BOOL receivedResponseHeaders; 52 | 53 | int queueFinishedCallCount; 54 | } 55 | - (void)testFailure; 56 | - (void)testFailureCancelsOtherRequests; 57 | - (void)testDownloadProgress; 58 | - (void)testUploadProgress; 59 | - (void)testProgressWithAuthentication; 60 | - (void)testWithNoListener; 61 | - (void)testPartialResume; 62 | - (void)testImmediateCancel; 63 | 64 | - (void)setProgress:(float)newProgress; 65 | - (void)testSubclass; 66 | - (void)testQueueReleaseOnRequestComplete; 67 | - (void)testQueueReleaseOnQueueComplete; 68 | 69 | - (void)testMultipleDownloadsThrottlingBandwidth; 70 | - (void)testMultipleUploadsThrottlingBandwidth; 71 | 72 | - (void)testDelegateAuthenticationCredentialsReuse; 73 | - (void)testPOSTWithAuthentication; 74 | - (void)testHEADFailure; 75 | @property (retain) NSOperationQueue *immediateCancelQueue; 76 | @property (retain) NSMutableArray *failedRequests; 77 | @property (retain) NSMutableArray *finishedRequests; 78 | @property (retain) ASINetworkQueue *releaseTestQueue; 79 | @property (retain) ASINetworkQueue *cancelQueue; 80 | @property (retain) ASINetworkQueue *postQueue; 81 | @property (retain) ASINetworkQueue *testNTLMQueue; 82 | @property (retain) ASINetworkQueue *addMoreRequestsQueue; 83 | @end 84 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications. 2 | 3 | It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files using multipart/form-data. 4 | 5 | It provides: 6 | * A straightforward interface for submitting data to and fetching data from webservers 7 | * Download data to memory or directly to a file on disk 8 | * Submit files on local drives as part of POST data, compatible with the HTML file input mechanism 9 | * Stream request bodies directly from disk to the server, to conserve memory 10 | * Resume for partial downloads 11 | * Easy access to request and response HTTP headers 12 | * Progress delegates (NSProgressIndicators and UIProgressViews) to show information about download AND upload progress 13 | * Auto-magic management of upload and download progress indicators for operation queues 14 | * Basic, Digest + NTLM authentication support, credentials are automatically re-used for the duration of a session, and can be stored for later in the Keychain. 15 | * Cookie support 16 | * [NEW] Requests can continue to run when your app moves to the background (iOS 4+) 17 | * GZIP support for response data AND request bodies 18 | * The included ASIDownloadCache class lets requests transparently cache responses, and allow requests for cached data to succeed even when there is no network available 19 | * [NEW] ASIWebPageRequest - download complete webpages, including external resources like images and stylesheets. Pages of any size can be indefinitely cached, and displayed in a UIWebview / WebView even when you have no network connection. 20 | * Easy to use support for Amazon S3 - no need to fiddle around signing requests yourself! 21 | * Full support for Rackspace Cloud Files 22 | * [NEW] Client certificates support 23 | * Supports manual and auto-detected proxies, authenticating proxies, and PAC file auto-configuration. The built-in login dialog lets your iPhone application work transparently with authenticating proxies without any additional effort. 24 | * Bandwidth throttling support 25 | * Support for persistent connections 26 | * Supports synchronous & asynchronous requests 27 | * Get notifications about changes in your request state via delegation or [NEW] blocks (Mac OS X 10.6, iOS 4 and above) 28 | * Comes with a broad range of unit tests 29 | 30 | ASIHTTPRequest is compatible with Mac OS 10.5 or later, and iOS 3.0 or later. 31 | 32 | Documentation is available "here":http://allseeing-i.com/ASIHTTPRequest. -------------------------------------------------------------------------------- /Classes/S3/ASIS3BucketRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3BucketRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Use this class to create buckets, fetch a list of their contents, and delete buckets 9 | 10 | #import 11 | #import "ASIS3Request.h" 12 | 13 | @class ASIS3BucketObject; 14 | 15 | @interface ASIS3BucketRequest : ASIS3Request { 16 | 17 | // Name of the bucket to talk to 18 | NSString *bucket; 19 | 20 | // A parameter passed to S3 in the query string to tell it to return specialised information 21 | // Consult the S3 REST API documentation for more info 22 | NSString *subResource; 23 | 24 | // Options for filtering GET requests 25 | // See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html 26 | NSString *prefix; 27 | NSString *marker; 28 | int maxResultCount; 29 | NSString *delimiter; 30 | 31 | // Internally used while parsing the response 32 | ASIS3BucketObject *currentObject; 33 | 34 | // Returns an array of ASIS3BucketObjects created from the XML response 35 | NSMutableArray *objects; 36 | 37 | // Will be populated with a list of 'folders' when a delimiter is set 38 | NSMutableArray *commonPrefixes; 39 | 40 | // Will be true if this request did not return all the results matching the query (use maxResultCount to configure the number of results to return) 41 | BOOL isTruncated; 42 | } 43 | 44 | // Fetch a bucket 45 | + (id)requestWithBucket:(NSString *)bucket; 46 | 47 | // Create a bucket request, passing a parameter in the query string 48 | // You'll need to parse the response XML yourself 49 | // Examples: 50 | // Fetch ACL: 51 | // ASIS3BucketRequest *request = [ASIS3BucketRequest requestWithBucket:@"mybucket" parameter:@"acl"]; 52 | // Fetch Location: 53 | // ASIS3BucketRequest *request = [ASIS3BucketRequest requestWithBucket:@"mybucket" parameter:@"location"]; 54 | // See the S3 REST API docs for more information about the parameters you can pass 55 | + (id)requestWithBucket:(NSString *)bucket subResource:(NSString *)subResource; 56 | 57 | // Use for creating new buckets 58 | + (id)PUTRequestWithBucket:(NSString *)bucket; 59 | 60 | // Use for deleting buckets - they must be empty for this to succeed 61 | + (id)DELETERequestWithBucket:(NSString *)bucket; 62 | 63 | @property (retain, nonatomic) NSString *bucket; 64 | @property (retain, nonatomic) NSString *subResource; 65 | @property (retain, nonatomic) NSString *prefix; 66 | @property (retain, nonatomic) NSString *marker; 67 | @property (assign, nonatomic) int maxResultCount; 68 | @property (retain, nonatomic) NSString *delimiter; 69 | @property (retain, readonly) NSMutableArray *objects; 70 | @property (retain, readonly) NSMutableArray *commonPrefixes; 71 | @property (assign, readonly) BOOL isTruncated; 72 | @end 73 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainerXMLParserDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainerXMLParserDelegate.m 3 | // 4 | // Created by Michael Mayo on 1/10/10. 5 | // 6 | 7 | #import "ASICloudFilesContainerXMLParserDelegate.h" 8 | #import "ASICloudFilesContainer.h" 9 | 10 | 11 | @implementation ASICloudFilesContainerXMLParserDelegate 12 | 13 | @synthesize containerObjects, currentElement, currentContent, currentObject; 14 | 15 | #pragma mark - 16 | #pragma mark XML Parser Delegate 17 | 18 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { 19 | [self setCurrentElement:elementName]; 20 | 21 | if ([elementName isEqualToString:@"container"]) { 22 | [self setCurrentObject:[ASICloudFilesContainer container]]; 23 | } 24 | [self setCurrentContent:@""]; 25 | } 26 | 27 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { 28 | 29 | if ([elementName isEqualToString:@"name"]) { 30 | [self currentObject].name = [self currentContent]; 31 | } else if ([elementName isEqualToString:@"count"]) { 32 | [self currentObject].count = [[self currentContent] intValue]; 33 | } else if ([elementName isEqualToString:@"bytes"]) { 34 | [self currentObject].bytes = [[self currentContent] intValue]; 35 | } else if ([elementName isEqualToString:@"cdn_enabled"]) { 36 | [self currentObject].cdnEnabled = [[self currentObject] isEqual:@"True"]; 37 | } else if ([elementName isEqualToString:@"ttl"]) { 38 | [self currentObject].ttl = [[self currentContent] intValue]; 39 | } else if ([elementName isEqualToString:@"cdn_url"]) { 40 | [self currentObject].cdnURL = [self currentContent]; 41 | } else if ([elementName isEqualToString:@"log_retention"]) { 42 | [self currentObject].logRetention = [[self currentObject] isEqual:@"True"]; 43 | } else if ([elementName isEqualToString:@"referrer_acl"]) { 44 | [self currentObject].referrerACL = [self currentContent]; 45 | } else if ([elementName isEqualToString:@"useragent_acl"]) { 46 | [self currentObject].useragentACL = [self currentContent]; 47 | } else if ([elementName isEqualToString:@"container"]) { 48 | // we're done with this container. time to move on to the next 49 | if (containerObjects == nil) { 50 | containerObjects = [[NSMutableArray alloc] init]; 51 | } 52 | [containerObjects addObject:currentObject]; 53 | [self setCurrentObject:nil]; 54 | } 55 | } 56 | 57 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 58 | [self setCurrentContent:[[self currentContent] stringByAppendingString:string]]; 59 | } 60 | 61 | #pragma mark - 62 | #pragma mark Memory Management 63 | 64 | - (void)dealloc { 65 | [containerObjects release]; 66 | [currentElement release]; 67 | [currentContent release]; 68 | [currentObject release]; 69 | [super dealloc]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3ServiceRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3ServiceRequest.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIS3ServiceRequest.h" 10 | #import "ASIS3Bucket.h" 11 | 12 | // Private stuff 13 | @interface ASIS3ServiceRequest () 14 | @property (retain) NSMutableArray *buckets; 15 | @property (retain, nonatomic) ASIS3Bucket *currentBucket; 16 | @property (retain, nonatomic) NSString *ownerID; 17 | @property (retain, nonatomic) NSString *ownerName; 18 | @end 19 | 20 | @implementation ASIS3ServiceRequest 21 | 22 | + (id)serviceRequest 23 | { 24 | ASIS3ServiceRequest *request = [[[self alloc] initWithURL:nil] autorelease]; 25 | return request; 26 | } 27 | 28 | - (id)initWithURL:(NSURL *)newURL 29 | { 30 | self = [super initWithURL:newURL]; 31 | [self setBuckets:[[[NSMutableArray alloc] init] autorelease]]; 32 | return self; 33 | } 34 | 35 | - (void)dealloc 36 | { 37 | [buckets release]; 38 | [currentBucket release]; 39 | [ownerID release]; 40 | [ownerName release]; 41 | [super dealloc]; 42 | } 43 | 44 | - (void)buildURL 45 | { 46 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@",[self requestScheme],[[self class] S3Host]]]]; 47 | } 48 | 49 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 50 | { 51 | if ([elementName isEqualToString:@"Bucket"]) { 52 | [self setCurrentBucket:[ASIS3Bucket bucketWithOwnerID:[self ownerID] ownerName:[self ownerName]]]; 53 | } 54 | [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict]; 55 | } 56 | 57 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 58 | { 59 | if ([elementName isEqualToString:@"Bucket"]) { 60 | [[self buckets] addObject:[self currentBucket]]; 61 | [self setCurrentBucket:nil]; 62 | } else if ([elementName isEqualToString:@"Name"]) { 63 | [[self currentBucket] setName:[self currentXMLElementContent]]; 64 | } else if ([elementName isEqualToString:@"CreationDate"]) { 65 | [[self currentBucket] setCreationDate:[[ASIS3Request S3ResponseDateFormatter] dateFromString:[self currentXMLElementContent]]]; 66 | } else if ([elementName isEqualToString:@"ID"]) { 67 | [self setOwnerID:[self currentXMLElementContent]]; 68 | } else if ([elementName isEqualToString:@"DisplayName"]) { 69 | [self setOwnerName:[self currentXMLElementContent]]; 70 | } else { 71 | // Let ASIS3Request look for error messages 72 | [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 73 | } 74 | } 75 | 76 | @synthesize buckets; 77 | @synthesize currentBucket; 78 | @synthesize ownerID; 79 | @synthesize ownerName; 80 | @end 81 | -------------------------------------------------------------------------------- /Classes/ASIFormDataRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIFormDataRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASIHTTPRequest.h" 11 | #import "ASIHTTPRequestConfig.h" 12 | 13 | typedef enum _ASIPostFormat { 14 | ASIMultipartFormDataPostFormat = 0, 15 | ASIURLEncodedPostFormat = 1 16 | 17 | } ASIPostFormat; 18 | 19 | @interface ASIFormDataRequest : ASIHTTPRequest { 20 | 21 | // Parameters that will be POSTed to the url 22 | NSMutableArray *postData; 23 | 24 | // Files that will be POSTed to the url 25 | NSMutableArray *fileData; 26 | 27 | ASIPostFormat postFormat; 28 | 29 | NSStringEncoding stringEncoding; 30 | 31 | #if DEBUG_FORM_DATA_REQUEST 32 | // 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 33 | NSString *debugBodyString; 34 | #endif 35 | 36 | } 37 | 38 | #pragma mark utilities 39 | - (NSString*)encodeURL:(NSString *)string; 40 | 41 | #pragma mark setup request 42 | 43 | // Add a POST variable to the request 44 | - (void)addPostValue:(id )value forKey:(NSString *)key; 45 | 46 | // Set a POST variable for this request, clearing any others with the same key 47 | - (void)setPostValue:(id )value forKey:(NSString *)key; 48 | 49 | // Add the contents of a local file to the request 50 | - (void)addFile:(NSString *)filePath forKey:(NSString *)key; 51 | 52 | // Same as above, but you can specify the content-type and file name 53 | - (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 54 | 55 | // Add the contents of a local file to the request, clearing any others with the same key 56 | - (void)setFile:(NSString *)filePath forKey:(NSString *)key; 57 | 58 | // Same as above, but you can specify the content-type and file name 59 | - (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 60 | 61 | // Add the contents of an NSData object to the request 62 | - (void)addData:(NSData *)data forKey:(NSString *)key; 63 | 64 | // Same as above, but you can specify the content-type and file name 65 | - (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 66 | 67 | // Add the contents of an NSData object to the request, clearing any others with the same key 68 | - (void)setData:(NSData *)data forKey:(NSString *)key; 69 | 70 | // Same as above, but you can specify the content-type and file name 71 | - (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 72 | 73 | 74 | @property (assign) ASIPostFormat postFormat; 75 | @property (assign) NSStringEncoding stringEncoding; 76 | @end 77 | -------------------------------------------------------------------------------- /iPhone Sample/SampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SampleViewController.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 17/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "SampleViewController.h" 10 | 11 | // Private stuff 12 | @interface SampleViewController () 13 | - (void)keyboardWillShow:(NSNotification *)notification; 14 | - (void)keyboardWillHide:(NSNotification *)notification; 15 | @end 16 | 17 | 18 | 19 | @implementation SampleViewController 20 | 21 | - (void)showNavigationButton:(UIBarButtonItem *)button 22 | { 23 | [[[self navigationBar] topItem] setLeftBarButtonItem:button animated:NO]; 24 | } 25 | 26 | - (void)hideNavigationButton:(UIBarButtonItem *)button 27 | { 28 | [[[self navigationBar] topItem] setLeftBarButtonItem:nil animated:NO]; 29 | } 30 | 31 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 32 | { 33 | return YES; 34 | } 35 | 36 | - (NSIndexPath *)tableView:(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 37 | { 38 | return nil; 39 | } 40 | 41 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 42 | { 43 | [[self tableView] reloadData]; 44 | } 45 | 46 | - (void)viewDidLoad 47 | { 48 | [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth]; 49 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 50 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 51 | } 52 | 53 | - (void)viewDidUnload { 54 | [super viewDidUnload]; 55 | [self setNavigationBar:nil]; 56 | [self setTableView:nil]; 57 | } 58 | 59 | - (void)keyboardWillShow:(NSNotification *)notification 60 | { 61 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2 62 | NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey]; 63 | #else 64 | NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey]; 65 | #endif 66 | CGRect keyboardBounds; 67 | [keyboardBoundsValue getValue:&keyboardBounds]; 68 | UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height-42, 0); 69 | [[self tableView] setScrollIndicatorInsets:e]; 70 | [[self tableView] setContentInset:e]; 71 | } 72 | 73 | - (void)keyboardWillHide:(NSNotification *)notification 74 | { 75 | UIEdgeInsets e = UIEdgeInsetsMake(0, 0, 0, 0); 76 | [[self tableView] setScrollIndicatorInsets:e]; 77 | [[self tableView] setContentInset:e]; 78 | } 79 | 80 | - (void)dealloc { 81 | [navigationBar release]; 82 | [tableView release]; 83 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 84 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; 85 | [super dealloc]; 86 | } 87 | 88 | @synthesize navigationBar; 89 | @synthesize tableView; 90 | @end 91 | -------------------------------------------------------------------------------- /iPhone Sample/GHUnitIOSTestMain.m: -------------------------------------------------------------------------------- 1 | // 2 | // GHUnitIOSTestMain.m 3 | // GHUnitIPhone 4 | // 5 | // Created by Gabriel Handford on 1/25/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | // If you are using the framework 33 | #import 34 | // If you are using the static library and importing header files manually 35 | //#import "GHUnit.h" 36 | 37 | // Default exception handler 38 | void exceptionHandler(NSException *exception) { 39 | NSLog(@"%@\n%@", [exception reason], GHUStackTraceFromException(exception)); 40 | } 41 | 42 | int main(int argc, char *argv[]) { 43 | 44 | /*! 45 | For debugging: 46 | Go into the "Get Info" contextual menu of your (test) executable (inside the "Executables" group in the left panel of XCode). 47 | Then go in the "Arguments" tab. You can add the following environment variables: 48 | 49 | Default: Set to: 50 | NSDebugEnabled NO "YES" 51 | NSZombieEnabled NO "YES" 52 | NSDeallocateZombies NO "YES" 53 | NSHangOnUncaughtException NO "YES" 54 | 55 | NSEnableAutoreleasePool YES "NO" 56 | NSAutoreleaseFreedObjectCheckEnabled NO "YES" 57 | NSAutoreleaseHighWaterMark 0 non-negative integer 58 | NSAutoreleaseHighWaterResolution 0 non-negative integer 59 | 60 | For info on these varaiables see NSDebug.h; http://theshadow.uw.hu/iPhoneSDKdoc/Foundation.framework/NSDebug.h.html 61 | 62 | For malloc debugging see: http://developer.apple.com/mac/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html 63 | */ 64 | 65 | NSSetUncaughtExceptionHandler(&exceptionHandler); 66 | 67 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 68 | 69 | // Register any special test case classes 70 | //[[GHTesting sharedInstance] registerClassName:@"GHSpecialTestCase"]; 71 | 72 | int retVal = 0; 73 | // If GHUNIT_CLI is set we are using the command line interface and run the tests 74 | // Otherwise load the GUI app 75 | if (getenv("GHUNIT_CLI")) { 76 | retVal = [GHTestRunner run]; 77 | } else { 78 | retVal = UIApplicationMain(argc, argv, nil, @"GHUnitIPhoneAppDelegate"); 79 | } 80 | [pool release]; 81 | return retVal; 82 | } -------------------------------------------------------------------------------- /Classes/Tests/ClientCertificateTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClientCertificateTests.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 18/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ClientCertificateTests.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | @implementation ClientCertificateTests 13 | 14 | - (void)testClientCertificate 15 | { 16 | // This test will fail the second time it is run, I presume the certificate is being cached somewhere 17 | 18 | // This url requires we present a client certificate to connect to it 19 | NSURL *url = [NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"]; 20 | 21 | // First, let's attempt to connect to the url without supplying a certificate 22 | ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; 23 | 24 | // We have to turn off validation for these tests, as the server has a self-signed certificate 25 | [request setValidatesSecureCertificate:NO]; 26 | [request startSynchronous]; 27 | 28 | GHAssertNotNil([request error],@"Request succeeded even though we presented no certificate, cannot proceed with test"); 29 | 30 | // Now, let's grab the certificate (included in the resources of the test app) 31 | SecIdentityRef identity = NULL; 32 | SecTrustRef trust = NULL; 33 | NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]]; 34 | [ClientCertificateTests extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]; 35 | 36 | request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"]]; 37 | 38 | // In this case, we have no need to add extra certificates, just the one inside the indentity will be used 39 | [request setClientCertificateIdentity:identity]; 40 | [request setValidatesSecureCertificate:NO]; 41 | [request startSynchronous]; 42 | 43 | // Make sure the request got the correct content 44 | GHAssertNil([request error],@"Request failed with error %@",[request error]); 45 | BOOL success = [[request responseString] isEqualToString:@"This is the expected content for the first string"]; 46 | GHAssertTrue(success,@"Request failed to download the correct content"); 47 | } 48 | 49 | // Based on code from http://developer.apple.com/mac/library/documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html 50 | 51 | + (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data 52 | { 53 | OSStatus securityError = errSecSuccess; 54 | 55 | NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"" forKey:(id)kSecImportExportPassphrase]; 56 | 57 | CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 58 | securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items); 59 | 60 | if (securityError == 0) { 61 | CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0); 62 | const void *tempIdentity = NULL; 63 | tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); 64 | *outIdentity = (SecIdentityRef)tempIdentity; 65 | const void *tempTrust = NULL; 66 | tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); 67 | *outTrust = (SecTrustRef)tempTrust; 68 | } else { 69 | NSLog(@"Failed with error code %d",(int)securityError); 70 | return NO; 71 | } 72 | return YES; 73 | } 74 | 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Classes/Tests/GHUnitTestMain.m: -------------------------------------------------------------------------------- 1 | // 2 | // GHUnitTestMain.m 3 | // GHUnit 4 | // 5 | // Created by Gabriel Handford on 2/22/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | #import 33 | #import 34 | #import 35 | 36 | // Default exception handler 37 | void exceptionHandler(NSException *exception) { 38 | NSLog(@"%@\n%@", [exception reason], GHUStackTraceFromException(exception)); 39 | } 40 | 41 | int main(int argc, char *argv[]) { 42 | 43 | /*! 44 | For debugging: 45 | Go into the "Get Info" contextual menu of your (test) executable (inside the "Executables" group in the left panel of XCode). 46 | Then go in the "Arguments" tab. You can add the following environment variables: 47 | 48 | Default: Set to: 49 | NSDebugEnabled NO "YES" 50 | NSZombieEnabled NO "YES" 51 | NSDeallocateZombies NO "YES" 52 | NSHangOnUncaughtException NO "YES" 53 | 54 | NSEnableAutoreleasePool YES "NO" 55 | NSAutoreleaseFreedObjectCheckEnabled NO "YES" 56 | NSAutoreleaseHighWaterMark 0 non-negative integer 57 | NSAutoreleaseHighWaterResolution 0 non-negative integer 58 | 59 | For info on these varaiables see NSDebug.h; http://theshadow.uw.hu/iPhoneSDKdoc/Foundation.framework/NSDebug.h.html 60 | 61 | For malloc debugging see: http://developer.apple.com/mac/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html 62 | */ 63 | 64 | NSSetUncaughtExceptionHandler(&exceptionHandler); 65 | 66 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 67 | 68 | // Register any special test case classes 69 | //[[GHTesting sharedInstance] registerClassName:@"GHSpecialTestCase"]; 70 | 71 | int retVal = 0; 72 | // If GHUNIT_CLI is set we are using the command line interface and run the tests 73 | // Otherwise load the GUI app 74 | if (getenv("GHUNIT_CLI")) { 75 | retVal = [GHTestRunner run]; 76 | } else { 77 | // To run all tests (from ENV) 78 | GHTestApp *app = [[GHTestApp alloc] init]; 79 | // To run a different test suite: 80 | //GHTestSuite *suite = [GHTestSuite suiteWithTestFilter:@"GHSlowTest,GHAsyncTestCaseTest"]; 81 | //GHTestApp *app = [[GHTestApp alloc] initWithSuite:suite]; 82 | // Or set global: 83 | //GHUnitTest = @"GHSlowTest"; 84 | [NSApp run]; 85 | [app release]; 86 | } 87 | [pool release]; 88 | return retVal; 89 | } 90 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesObjectRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesObjectRequest.h 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASICloudFilesRequest.h" 8 | 9 | #if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) 10 | #import "ASINSXMLParserCompat.h" 11 | #endif 12 | 13 | @class ASICloudFilesObject; 14 | 15 | @interface ASICloudFilesObjectRequest : ASICloudFilesRequest { 16 | 17 | 18 | NSString *accountName; 19 | NSString *containerName; 20 | 21 | // Internally used while parsing the response 22 | NSString *currentContent; 23 | NSString *currentElement; 24 | ASICloudFilesObject *currentObject; 25 | NSMutableArray *objects; 26 | 27 | } 28 | 29 | @property (retain) NSString *accountName; 30 | @property (retain) NSString *containerName; 31 | @property (retain) NSString *currentElement; 32 | @property (retain) NSString *currentContent; 33 | @property (retain) ASICloudFilesObject *currentObject; 34 | 35 | 36 | // HEAD /// 37 | // HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used. 38 | + (id)containerInfoRequest:(NSString *)containerName; 39 | - (NSUInteger)containerObjectCount; 40 | - (NSUInteger)containerBytesUsed; 41 | 42 | // HEAD //// 43 | // to get metadata 44 | + (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath; 45 | - (NSArray *)objects; 46 | 47 | + (id)listRequestWithContainer:(NSString *)containerName; 48 | + (id)listRequestWithContainer:(NSString *)containerName limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path; 49 | 50 | // Conditional GET headers: If-Match • If-None-Match • If-Modified-Since • If-Unmodified-Since 51 | // HTTP Range header: “Range: bytes=0-5” • “Range: bytes=-5” • “Range: bytes=32-“ 52 | + (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath; 53 | - (ASICloudFilesObject *)object; 54 | 55 | // PUT //// 56 | // PUT operations are used to write, or overwrite, an Object's metadata and content. 57 | // The Object can be created with custom metadata via HTTP headers identified with the “X-Object-Meta-” prefix. 58 | + (id)putObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object; 59 | + (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType objectData:(NSData *)objectData metadata:(NSDictionary *)metadata etag:(NSString *)etag; 60 | + (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType file:(NSString *)filePath metadata:(NSDictionary *)metadata etag:(NSString *)etag; 61 | 62 | // POST //// 63 | // POST operations against an Object name are used to set and overwrite arbitrary key/value metadata. You cannot use the POST operation to change any of the Object's other headers such as Content-Type, ETag, etc. It is not used to upload storage Objects (see PUT). 64 | // A POST request will delete all existing metadata added with a previous PUT/POST. 65 | + (id)postObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object; 66 | + (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata; 67 | 68 | // DELETE //// 69 | + (id)deleteObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /Classes/ASIInputStream.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIInputStream.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 10/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIInputStream.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | // Used to ensure only one request can read data at once 13 | static NSLock *readLock = nil; 14 | 15 | @implementation ASIInputStream 16 | 17 | + (void)initialize 18 | { 19 | if (self == [ASIInputStream class]) { 20 | readLock = [[NSLock alloc] init]; 21 | } 22 | } 23 | 24 | + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest 25 | { 26 | ASIInputStream *theStream = [[[self alloc] init] autorelease]; 27 | [theStream setRequest:theRequest]; 28 | [theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]]; 29 | return theStream; 30 | } 31 | 32 | + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest 33 | { 34 | ASIInputStream *theStream = [[[self alloc] init] autorelease]; 35 | [theStream setRequest:theRequest]; 36 | [theStream setStream:[NSInputStream inputStreamWithData:data]]; 37 | return theStream; 38 | } 39 | 40 | - (void)dealloc 41 | { 42 | [stream release]; 43 | [super dealloc]; 44 | } 45 | 46 | // Called when CFNetwork wants to read more of our request body 47 | // When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read 48 | - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len 49 | { 50 | [readLock lock]; 51 | unsigned long toRead = len; 52 | if ([ASIHTTPRequest isBandwidthThrottled]) { 53 | toRead = [ASIHTTPRequest maxUploadReadLength]; 54 | if (toRead > len) { 55 | toRead = len; 56 | } else if (toRead == 0) { 57 | toRead = 1; 58 | } 59 | [request performThrottling]; 60 | } 61 | [readLock unlock]; 62 | NSInteger rv = [stream read:buffer maxLength:toRead]; 63 | if (rv > 0) 64 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:rv]; 65 | return rv; 66 | } 67 | 68 | /* 69 | * Implement NSInputStream mandatory methods to make sure they are implemented 70 | * (necessary for MacRuby for example) and avoid the overhead of method 71 | * forwarding for these common methods. 72 | */ 73 | - (void)open 74 | { 75 | [stream open]; 76 | } 77 | 78 | - (void)close 79 | { 80 | [stream close]; 81 | } 82 | 83 | - (id)delegate 84 | { 85 | return [stream delegate]; 86 | } 87 | 88 | - (void)setDelegate:(id)delegate 89 | { 90 | [stream setDelegate:delegate]; 91 | } 92 | 93 | - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 94 | { 95 | [stream scheduleInRunLoop:aRunLoop forMode:mode]; 96 | } 97 | 98 | - (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 99 | { 100 | [stream removeFromRunLoop:aRunLoop forMode:mode]; 101 | } 102 | 103 | - (id)propertyForKey:(NSString *)key 104 | { 105 | return [stream propertyForKey:key]; 106 | } 107 | 108 | - (BOOL)setProperty:(id)property forKey:(NSString *)key 109 | { 110 | return [stream setProperty:property forKey:key]; 111 | } 112 | 113 | - (NSStreamStatus)streamStatus 114 | { 115 | return [stream streamStatus]; 116 | } 117 | 118 | - (NSError *)streamError 119 | { 120 | return [stream streamError]; 121 | } 122 | 123 | // If we get asked to perform a method we don't have (probably internal ones), 124 | // we'll just forward the message to our stream 125 | 126 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 127 | { 128 | return [stream methodSignatureForSelector:aSelector]; 129 | } 130 | 131 | - (void)forwardInvocation:(NSInvocation *)anInvocation 132 | { 133 | [anInvocation invokeWithTarget:stream]; 134 | } 135 | 136 | @synthesize stream; 137 | @synthesize request; 138 | @end 139 | -------------------------------------------------------------------------------- /Classes/ASIWebPageRequest/ASIWebPageRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIWebPageRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 29/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // This is an EXPERIMENTAL class - use at your own risk! 9 | // It is strongly recommend to set a downloadDestinationPath when using ASIWebPageRequest 10 | // Also, performance will be better if your ASIWebPageRequest has a downloadCache setup 11 | // Known issue: You cannot use startSychronous with an ASIWebPageRequest 12 | 13 | #import "ASIHTTPRequest.h" 14 | #import 15 | #import 16 | #import 17 | #import 18 | 19 | @class ASINetworkQueue; 20 | 21 | // Used internally for storing what type of data we got from the server 22 | typedef enum _ASIWebContentType { 23 | ASINotParsedWebContentType = 0, 24 | ASIHTMLWebContentType = 1, 25 | ASICSSWebContentType = 2 26 | } ASIWebContentType; 27 | 28 | // These correspond with the urlReplacementMode property of ASIWebPageRequest 29 | typedef enum _ASIURLReplacementMode { 30 | 31 | // Don't modify html or css content at all 32 | ASIDontModifyURLs = 0, 33 | 34 | // Replace external resources urls (images, stylesheets etc) with data uris, so their content is embdedded directly in the html/css 35 | ASIReplaceExternalResourcesWithData = 1, 36 | 37 | // Replace external resource urls with the url of locally cached content 38 | // You must set the baseURL of a WebView / UIWebView to a file url pointing at the downloadDestinationPath of the main ASIWebPageRequest if you want to display your content 39 | // See the Mac or iPhone example projects for a demonstration of how to do this 40 | // The hrefs of all hyperlinks are changed to use absolute urls when using this mode 41 | ASIReplaceExternalResourcesWithLocalURLs = 2 42 | } ASIURLReplacementMode; 43 | 44 | 45 | 46 | @interface ASIWebPageRequest : ASIHTTPRequest { 47 | 48 | // Each ASIWebPageRequest for an HTML or CSS file creates its own internal queue to download external resources 49 | ASINetworkQueue *externalResourceQueue; 50 | 51 | // This dictionary stores a list of external resources to download, along with their content-type data or a path to the data 52 | NSMutableDictionary *resourceList; 53 | 54 | // Used internally for parsing HTML (with libxml) 55 | xmlDocPtr doc; 56 | 57 | // If the response is an HTML or CSS file, this will be set so the content can be correctly parsed when it has finished fetching external resources 58 | ASIWebContentType webContentType; 59 | 60 | // Stores a reference to the ASIWebPageRequest that created this request 61 | // Note that a parentRequest can also have a parent request because ASIWebPageRequests parse their contents to look for external resources recursively 62 | // For example, a request for an image can be created by a request for a stylesheet which was created by a request for a web page 63 | ASIWebPageRequest *parentRequest; 64 | 65 | // Controls what ASIWebPageRequest does with external resources. See the notes above for more. 66 | ASIURLReplacementMode urlReplacementMode; 67 | } 68 | 69 | // Will return a data URI that contains a base64 version of the content at this url 70 | // This is used when replacing urls in the html and css with actual data 71 | // If you subclass ASIWebPageRequest, you can override this function to return different content or a url pointing at another location 72 | - (NSString *)contentForExternalURL:(NSString *)theURL; 73 | 74 | // Returns the location that a downloaded external resource's content will be stored in 75 | - (NSString *)cachePathForRequest:(ASIWebPageRequest *)theRequest; 76 | 77 | 78 | @property (retain, nonatomic) ASIWebPageRequest *parentRequest; 79 | @property (assign, nonatomic) ASIURLReplacementMode urlReplacementMode; 80 | @end 81 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3ObjectRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3ObjectRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Use an ASIS3ObjectRequest to fetch, upload, copy and delete objects on Amazon S3 9 | 10 | #import 11 | #import "ASIS3Request.h" 12 | 13 | // Constants for storage class 14 | extern NSString *const ASIS3StorageClassStandard; 15 | extern NSString *const ASIS3StorageClassReducedRedundancy; 16 | 17 | @interface ASIS3ObjectRequest : ASIS3Request { 18 | 19 | // Name of the bucket to talk to 20 | NSString *bucket; 21 | 22 | // Key of the resource you want to access on S3 23 | NSString *key; 24 | 25 | // The bucket + path of the object to be copied (used with COPYRequestFromBucket:path:toBucket:path:) 26 | NSString *sourceBucket; 27 | NSString *sourceKey; 28 | 29 | // The mime type of the content for PUT requests 30 | // Set this if having the correct mime type returned to you when you GET the data is important (eg it will be served by a web-server) 31 | // Can be autodetected when PUTing a file from disk, will default to 'application/octet-stream' when PUTing data 32 | NSString *mimeType; 33 | 34 | // Set this to specify you want to work with a particular subresource (eg an acl for that resource) 35 | // See requestWithBucket:key:subResource:, below. 36 | NSString* subResource; 37 | 38 | // The storage class to be used for PUT requests 39 | // Set this to ASIS3StorageClassReducedRedundancy to save money on storage, at (presumably) a slightly higher risk you will lose the data 40 | // If this is not set, no x-amz-storage-class header will be sent to S3, and their default will be used 41 | NSString *storageClass; 42 | } 43 | 44 | // Create a request, building an appropriate url 45 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key; 46 | 47 | // Create a request for an object, passing a parameter in the query string 48 | // You'll need to parse the response XML yourself 49 | // Examples: 50 | // Fetch ACL: 51 | // ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:@"mybucket" key:@"my-key" parameter:@"acl"]; 52 | // Get object torret: 53 | // ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:@"mybucket" key:@"my-key" parameter:@"torrent"]; 54 | // See the S3 REST API docs for more information about the parameters you can pass 55 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key subResource:(NSString *)subResource; 56 | 57 | // Create a PUT request using the file at filePath as the body 58 | + (id)PUTRequestForFile:(NSString *)filePath withBucket:(NSString *)bucket key:(NSString *)key; 59 | 60 | // Create a PUT request using the supplied NSData as the body (set the mime-type manually with setMimeType: if necessary) 61 | + (id)PUTRequestForData:(NSData *)data withBucket:(NSString *)bucket key:(NSString *)key; 62 | 63 | // Create a DELETE request for the object at path 64 | + (id)DELETERequestWithBucket:(NSString *)bucket key:(NSString *)key; 65 | 66 | // Create a PUT request to copy an object from one location to another 67 | // Clang will complain because it thinks this method should return an object with +1 retain :( 68 | + (id)COPYRequestFromBucket:(NSString *)sourceBucket key:(NSString *)sourceKey toBucket:(NSString *)bucket key:(NSString *)key; 69 | 70 | // Creates a HEAD request for the object at path 71 | + (id)HEADRequestWithBucket:(NSString *)bucket key:(NSString *)key; 72 | 73 | @property (retain, nonatomic) NSString *bucket; 74 | @property (retain, nonatomic) NSString *key; 75 | @property (retain, nonatomic) NSString *sourceBucket; 76 | @property (retain, nonatomic) NSString *sourceKey; 77 | @property (retain, nonatomic) NSString *mimeType; 78 | @property (retain, nonatomic) NSString *subResource; 79 | @property (retain, nonatomic) NSString *storageClass; 80 | @end 81 | -------------------------------------------------------------------------------- /Classes/Tests/BlocksTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // BlocksTests.m 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 18/10/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "BlocksTests.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | 13 | @implementation BlocksTests 14 | 15 | // ASIHTTPRequest always calls blocks on the main thread (just like it does with delegate methods) 16 | // So, we'll force this request to run on the main thread so we can rely on blocks having been called before the request returns 17 | - (BOOL)shouldRunOnMainThread { return YES; } 18 | 19 | #if NS_BLOCKS_AVAILABLE 20 | #if TARGET_OS_IPHONE 21 | // It isn't safe to allow the view to deallocate on a thread other than the main thread / web thread, so this test is designed to cause a crash semi-reliably 22 | - (void)testBlockMainThreadSafety 23 | { 24 | NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"]; 25 | UIWebView *webView = [[[UIWebView alloc] initWithFrame:CGRectMake(0,0,200,200)] autorelease]; 26 | __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; 27 | [request setCompletionBlock:^ {[webView loadHTMLString:[request responseString] baseURL:url]; }]; 28 | [request startAsynchronous]; 29 | } 30 | #endif 31 | 32 | - (void)testBlocks 33 | { 34 | NSData *dataToSend = [@"This is my post body" dataUsingEncoding:NSUTF8StringEncoding]; 35 | 36 | __block BOOL started = NO; 37 | __block BOOL receivedHeaders = NO; 38 | __block BOOL complete = NO; 39 | __block BOOL failed = NO; 40 | __block unsigned long long totalBytesReceived = 0; 41 | __block unsigned long long totalDownloadSize = 0; 42 | __block unsigned long long totalBytesSent = 0; 43 | __block unsigned long long totalUploadSize = 0; 44 | NSMutableData *dataReceived = [NSMutableData data]; 45 | 46 | // There's actually no need for us to use '__block' here, because we aren't using the request inside any of our blocks, but it's good to get into the habit of doing this anyway. 47 | __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/blocks"]]; 48 | [request setStartedBlock:^{ 49 | started = YES; 50 | }]; 51 | [request setHeadersReceivedBlock:^(NSDictionary *headers) { 52 | receivedHeaders = YES; 53 | }]; 54 | [request setCompletionBlock:^{ 55 | complete = YES; 56 | }]; 57 | [request setFailedBlock:^{ 58 | failed = YES; 59 | }]; 60 | [request setBytesReceivedBlock:^(unsigned long long length, unsigned long long total) { 61 | totalBytesReceived += length; 62 | }]; 63 | [request setDownloadSizeIncrementedBlock:^(long long length){ 64 | totalDownloadSize += length; 65 | }]; 66 | [request setBytesSentBlock:^(unsigned long long length, unsigned long long total) { 67 | totalBytesSent += length; 68 | }]; 69 | [request setUploadSizeIncrementedBlock:^(long long length){ 70 | totalUploadSize += length; 71 | }]; 72 | [request setDataReceivedBlock:^(NSData *data){ 73 | [dataReceived appendData:data]; 74 | }]; 75 | 76 | [request setRequestMethod:@"PUT"]; 77 | [request appendPostData:dataToSend]; 78 | [request startSynchronous]; 79 | 80 | GHAssertFalse(failed,@"Request failed, cannot proceed with test"); 81 | GHAssertTrue(started,@"Failed to call started block"); 82 | GHAssertTrue(receivedHeaders,@"Failed to call received headers block"); 83 | GHAssertTrue(complete,@"Failed to call completed block"); 84 | 85 | BOOL success = (totalBytesReceived == 457); 86 | GHAssertTrue(success,@"Failed to call bytes received block, or got wrong amount of data"); 87 | success = (totalDownloadSize == 457); 88 | GHAssertTrue(success,@"Failed to call download size increment block"); 89 | 90 | success = (totalBytesSent == [dataToSend length]); 91 | GHAssertTrue(success,@"Failed to call bytes sent block"); 92 | success = (totalUploadSize == [dataToSend length]); 93 | GHAssertTrue(success,@"Failed to call upload size increment block"); 94 | 95 | 96 | request = [ASIHTTPRequest requestWithURL:nil]; 97 | [request setFailedBlock:^{ 98 | failed = YES; 99 | }]; 100 | [request startSynchronous]; 101 | GHAssertTrue(failed,@"Failed to call request failure block"); 102 | } 103 | #endif 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesRequest.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Michael Mayo on 22/12/09. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | // A class for accessing data stored on Rackspace's Cloud Files Service 9 | // http://www.rackspacecloud.com/cloud_hosting_products/files 10 | // 11 | // Cloud Files Developer Guide: 12 | // http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf 13 | 14 | #import "ASICloudFilesRequest.h" 15 | 16 | static NSString *username = nil; 17 | static NSString *apiKey = nil; 18 | static NSString *authToken = nil; 19 | static NSString *storageURL = nil; 20 | static NSString *cdnManagementURL = nil; 21 | static NSString *rackspaceCloudAuthURL = @"https://auth.api.rackspacecloud.com/v1.0"; 22 | 23 | static NSRecursiveLock *accessDetailsLock = nil; 24 | 25 | @implementation ASICloudFilesRequest 26 | 27 | + (void)initialize 28 | { 29 | if (self == [ASICloudFilesRequest class]) { 30 | accessDetailsLock = [[NSRecursiveLock alloc] init]; 31 | } 32 | } 33 | 34 | #pragma mark - 35 | #pragma mark Attributes and Service URLs 36 | 37 | + (NSString *)authToken { 38 | return authToken; 39 | } 40 | 41 | + (NSString *)storageURL { 42 | return storageURL; 43 | } 44 | 45 | + (NSString *)cdnManagementURL { 46 | return cdnManagementURL; 47 | } 48 | 49 | #pragma mark - 50 | #pragma mark Authentication 51 | 52 | + (id)authenticationRequest 53 | { 54 | [accessDetailsLock lock]; 55 | ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]] autorelease]; 56 | [request addRequestHeader:@"X-Auth-User" value:username]; 57 | [request addRequestHeader:@"X-Auth-Key" value:apiKey]; 58 | [accessDetailsLock unlock]; 59 | return request; 60 | } 61 | 62 | + (NSError *)authenticate 63 | { 64 | [accessDetailsLock lock]; 65 | ASIHTTPRequest *request = [ASICloudFilesRequest authenticationRequest]; 66 | [request startSynchronous]; 67 | 68 | if (![request error]) { 69 | NSDictionary *responseHeaders = [request responseHeaders]; 70 | authToken = [responseHeaders objectForKey:@"X-Auth-Token"]; 71 | storageURL = [responseHeaders objectForKey:@"X-Storage-Url"]; 72 | cdnManagementURL = [responseHeaders objectForKey:@"X-CDN-Management-Url"]; 73 | 74 | // there is a bug in the Cloud Files API for some older accounts that causes 75 | // the CDN URL to come back in a slightly different header 76 | if (!cdnManagementURL) { 77 | cdnManagementURL = [responseHeaders objectForKey:@"X-Cdn-Management-Url"]; 78 | } 79 | } 80 | [accessDetailsLock unlock]; 81 | return [request error]; 82 | } 83 | 84 | + (NSString *)username 85 | { 86 | return username; 87 | } 88 | 89 | + (void)setUsername:(NSString *)newUsername 90 | { 91 | [accessDetailsLock lock]; 92 | [username release]; 93 | username = [newUsername retain]; 94 | [accessDetailsLock unlock]; 95 | } 96 | 97 | + (NSString *)apiKey { 98 | return apiKey; 99 | } 100 | 101 | + (void)setApiKey:(NSString *)newApiKey 102 | { 103 | [accessDetailsLock lock]; 104 | [apiKey release]; 105 | apiKey = [newApiKey retain]; 106 | [accessDetailsLock unlock]; 107 | } 108 | 109 | #pragma mark - 110 | #pragma mark Date Parser 111 | 112 | -(NSDate *)dateFromString:(NSString *)dateString 113 | { 114 | // We store our date formatter in the calling thread's dictionary 115 | // NSDateFormatter is not thread-safe, this approach ensures each formatter is only used on a single thread 116 | // This formatter can be reused many times in parsing a single response, so it would be expensive to keep creating new date formatters 117 | NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; 118 | NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASICloudFilesResponseDateFormatter"]; 119 | if (dateFormatter == nil) { 120 | dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; 121 | [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]]; 122 | // example: 2009-11-04T19:46:20.192723 123 | [dateFormatter setDateFormat:@"yyyy-MM-dd'T'H:mm:ss.SSSSSS"]; 124 | [threadDict setObject:dateFormatter forKey:@"ASICloudFilesResponseDateFormatter"]; 125 | } 126 | return [dateFormatter dateFromString:dateString]; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /iPhone Sample/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 16/06/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "SynchronousViewController.h" 11 | #import "QueueViewController.h" 12 | #import "AuthenticationViewController.h" 13 | #import "UploadViewController.h" 14 | #import "WebPageViewController.h" 15 | 16 | @implementation RootViewController 17 | 18 | 19 | - (void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | self.contentSizeForViewInPopover = CGSizeMake(310.0f, self.tableView.rowHeight*5.0f); 23 | } 24 | 25 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 26 | return YES; 27 | } 28 | 29 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 30 | { 31 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"]; 32 | if (!cell) { 33 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyCell"] autorelease]; 34 | } 35 | switch ([indexPath row]) { 36 | case 0: 37 | [[cell textLabel] setText:@"Synchronous"]; 38 | break; 39 | case 1: 40 | [[cell textLabel] setText:@"Queue"]; 41 | break; 42 | case 2: 43 | [[cell textLabel] setText:@"Authentication"]; 44 | break; 45 | case 3: 46 | [[cell textLabel] setText:@"Upload"]; 47 | break; 48 | case 4: 49 | [[cell textLabel] setText:@"Web Page Download"]; 50 | break; 51 | } 52 | return cell; 53 | } 54 | 55 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 56 | { 57 | return 5; 58 | } 59 | 60 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 61 | { 62 | UIViewController *viewController = nil; 63 | switch ([indexPath row]) { 64 | case 0: 65 | viewController = [[[SynchronousViewController alloc] initWithNibName:@"Sample" bundle:nil] autorelease]; 66 | break; 67 | case 1: 68 | viewController = [[[QueueViewController alloc] initWithNibName:@"Sample" bundle:nil] autorelease]; 69 | break; 70 | case 2: 71 | viewController = [[[AuthenticationViewController alloc] initWithNibName:@"Sample" bundle:nil] autorelease]; 72 | break; 73 | case 3: 74 | viewController = [[[UploadViewController alloc] initWithNibName:@"Sample" bundle:nil] autorelease]; 75 | break; 76 | case 4: 77 | viewController = [[[WebPageViewController alloc] initWithNibName:@"Sample" bundle:nil] autorelease]; 78 | break; 79 | } 80 | [splitViewController setViewControllers:[NSArray arrayWithObjects:[self navigationController],viewController,nil]]; 81 | 82 | // Dismiss the popover if it's present. 83 | if ([self popoverController]) { 84 | [[self popoverController] dismissPopoverAnimated:YES]; 85 | } 86 | 87 | // Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created). 88 | if ([self rootPopoverButtonItem]) { 89 | [[[(id)viewController navigationBar] topItem] setLeftBarButtonItem:[self rootPopoverButtonItem] animated:NO]; 90 | } 91 | 92 | } 93 | 94 | - (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc 95 | { 96 | [barButtonItem setTitle:@"More Examples"]; 97 | [self setPopoverController:pc]; 98 | [self setRootPopoverButtonItem:barButtonItem]; 99 | SampleViewController *detailViewController = [[splitViewController viewControllers] objectAtIndex:1]; 100 | [detailViewController showNavigationButton:barButtonItem]; 101 | } 102 | 103 | - (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem 104 | { 105 | [self setPopoverController:nil]; 106 | [self setRootPopoverButtonItem:nil]; 107 | SampleViewController *detailViewController = [[splitViewController viewControllers] objectAtIndex:1]; 108 | [detailViewController hideNavigationButton:barButtonItem]; 109 | } 110 | 111 | - (void)splitViewController:(UISplitViewController *)svc popoverController: (UIPopoverController *)pc willPresentViewController: (UIViewController *)aViewController 112 | { 113 | if (pc != nil) { 114 | [pc dismissPopoverAnimated:YES]; 115 | } 116 | } 117 | 118 | 119 | @synthesize splitViewController; 120 | @synthesize popoverController; 121 | @synthesize rootPopoverButtonItem; 122 | @end 123 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3Request.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3Request.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 30/06/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | // A class for accessing data stored on Amazon's Simple Storage Service (http://aws.amazon.com/s3/) using the REST API 9 | // While you can use this class directly, the included subclasses make typical operations easier 10 | 11 | #import 12 | #import "ASIHTTPRequest.h" 13 | 14 | #if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) 15 | #import "ASINSXMLParserCompat.h" 16 | #endif 17 | 18 | // See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAccessPolicy.html for what these mean 19 | extern NSString *const ASIS3AccessPolicyPrivate; // This is the default in S3 when no access policy header is provided 20 | extern NSString *const ASIS3AccessPolicyPublicRead; 21 | extern NSString *const ASIS3AccessPolicyPublicReadWrite; 22 | extern NSString *const ASIS3AccessPolicyAuthenticatedRead; 23 | extern NSString *const ASIS3AccessPolicyBucketOwnerRead; 24 | extern NSString *const ASIS3AccessPolicyBucketOwnerFullControl; 25 | 26 | // Constants for requestScheme - defaults is ASIS3RequestSchemeHTTP 27 | extern NSString *const ASIS3RequestSchemeHTTP; 28 | extern NSString *const ASIS3RequestSchemeHTTPS; 29 | 30 | 31 | 32 | typedef enum _ASIS3ErrorType { 33 | ASIS3ResponseParsingFailedType = 1, 34 | ASIS3ResponseErrorType = 2 35 | } ASIS3ErrorType; 36 | 37 | 38 | 39 | @interface ASIS3Request : ASIHTTPRequest { 40 | 41 | // Your S3 access key. Set it on the request, or set it globally using [ASIS3Request setSharedAccessKey:] 42 | NSString *accessKey; 43 | 44 | // Your S3 secret access key. Set it on the request, or set it globally using [ASIS3Request setSharedSecretAccessKey:] 45 | NSString *secretAccessKey; 46 | 47 | // Set to ASIS3RequestSchemeHTTPS to send your requests via HTTPS (default is ASIS3RequestSchemeHTTP) 48 | NSString *requestScheme; 49 | 50 | // The string that will be used in the HTTP date header. Generally you'll want to ignore this and let the class add the current date for you, but the accessor is used by the tests 51 | NSString *dateString; 52 | 53 | // The access policy to use when PUTting a file (see the string constants at the top ASIS3Request.h for details on what the possible options are) 54 | NSString *accessPolicy; 55 | 56 | // Internally used while parsing errors 57 | NSString *currentXMLElementContent; 58 | NSMutableArray *currentXMLElementStack; 59 | } 60 | 61 | // Uses the supplied date to create a Date header string 62 | - (void)setDate:(NSDate *)date; 63 | 64 | // Will return a dictionary of the 'amz-' headers that wil be sent to S3 65 | // Override in subclasses to add new ones 66 | - (NSMutableDictionary *)S3Headers; 67 | 68 | // Returns the string that will used to create a signature for this request 69 | // Is overridden in ASIS3ObjectRequest 70 | - (NSString *)stringToSignForHeaders:(NSString *)canonicalizedAmzHeaders resource:(NSString *)canonicalizedResource; 71 | 72 | // Parses the response to work out if S3 returned an error 73 | - (void)parseResponseXML; 74 | 75 | #pragma mark shared access keys 76 | 77 | // Get and set the global access key, this will be used for all requests the access key hasn't been set for 78 | + (NSString *)sharedAccessKey; 79 | + (void)setSharedAccessKey:(NSString *)newAccessKey; 80 | + (NSString *)sharedSecretAccessKey; 81 | + (void)setSharedSecretAccessKey:(NSString *)newAccessKey; 82 | 83 | # pragma mark helpers 84 | 85 | // Returns a date formatter than can be used to parse a date from S3 86 | + (NSDateFormatter*)S3ResponseDateFormatter; 87 | 88 | // Returns a date formatter than can be used to send a date header to S3 89 | + (NSDateFormatter*)S3RequestDateFormatter; 90 | 91 | 92 | // URL-encodes an S3 key so it can be used in a url 93 | // You shouldn't normally need to use this yourself 94 | + (NSString *)stringByURLEncodingForS3Path:(NSString *)key; 95 | 96 | // Returns a string for the hostname used for S3 requests. You shouldn't ever need to change this. 97 | + (NSString *)S3Host; 98 | 99 | // This is called automatically before the request starts to build the request URL (if one has not been manually set already) 100 | - (void)buildURL; 101 | 102 | @property (retain) NSString *dateString; 103 | @property (retain) NSString *accessKey; 104 | @property (retain) NSString *secretAccessKey; 105 | @property (retain) NSString *accessPolicy; 106 | @property (retain) NSString *currentXMLElementContent; 107 | @property (retain) NSMutableArray *currentXMLElementStack; 108 | @property (retain) NSString *requestScheme; 109 | @end 110 | -------------------------------------------------------------------------------- /Classes/ASINetworkQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASINetworkQueue.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASIHTTPRequestDelegate.h" 11 | #import "ASIProgressDelegate.h" 12 | 13 | @interface ASINetworkQueue : NSOperationQueue { 14 | 15 | // Delegate will get didFail + didFinish messages (if set) 16 | id delegate; 17 | 18 | // Will be called when a request starts with the request as the argument 19 | SEL requestDidStartSelector; 20 | 21 | // Will be called when a request receives response headers 22 | // Should take the form request:didRecieveResponseHeaders:, where the first argument is the request, and the second the headers dictionary 23 | SEL requestDidReceiveResponseHeadersSelector; 24 | 25 | // Will be called when a request is about to redirect 26 | // Should take the form request:willRedirectToURL:, where the first argument is the request, and the second the new url 27 | SEL requestWillRedirectSelector; 28 | 29 | // Will be called when a request completes with the request as the argument 30 | SEL requestDidFinishSelector; 31 | 32 | // Will be called when a request fails with the request as the argument 33 | SEL requestDidFailSelector; 34 | 35 | // Will be called when the queue finishes with the queue as the argument 36 | SEL queueDidFinishSelector; 37 | 38 | // Upload progress indicator, probably an NSProgressIndicator or UIProgressView 39 | id uploadProgressDelegate; 40 | 41 | // Total amount uploaded so far for all requests in this queue 42 | unsigned long long bytesUploadedSoFar; 43 | 44 | // 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 45 | unsigned long long totalBytesToUpload; 46 | 47 | // Download progress indicator, probably an NSProgressIndicator or UIProgressView 48 | id downloadProgressDelegate; 49 | 50 | // Total amount downloaded so far for all requests in this queue 51 | unsigned long long bytesDownloadedSoFar; 52 | 53 | // Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers 54 | unsigned long long totalBytesToDownload; 55 | 56 | // When YES, the queue will cancel all requests when a request fails. Default is YES 57 | BOOL shouldCancelAllRequestsOnFailure; 58 | 59 | //Number of real requests (excludes HEAD requests created to manage showAccurateProgress) 60 | int requestsCount; 61 | 62 | // When NO, this request will only update the progress indicator when it completes 63 | // When YES, this request will update the progress indicator according to how much data it has received so far 64 | // 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 65 | // 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 66 | // Set to YES if the size of a requests in the queue varies greatly for much more accurate results 67 | // Default for requests in the queue is NO 68 | BOOL showAccurateProgress; 69 | 70 | // Storage container for additional queue information. 71 | NSDictionary *userInfo; 72 | 73 | } 74 | 75 | // Convenience constructor 76 | + (id)queue; 77 | 78 | // Call this to reset a queue - it will cancel all operations, clear delegates, and suspend operation 79 | - (void)reset; 80 | 81 | // Used internally to manage HEAD requests when showAccurateProgress is YES, do not use! 82 | - (void)addHEADOperation:(NSOperation *)operation; 83 | 84 | // All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts 85 | // This method will start the queue 86 | - (void)go; 87 | 88 | @property (assign, nonatomic, setter=setUploadProgressDelegate:) id uploadProgressDelegate; 89 | @property (assign, nonatomic, setter=setDownloadProgressDelegate:) id downloadProgressDelegate; 90 | 91 | @property (assign) SEL requestDidStartSelector; 92 | @property (assign) SEL requestDidReceiveResponseHeadersSelector; 93 | @property (assign) SEL requestWillRedirectSelector; 94 | @property (assign) SEL requestDidFinishSelector; 95 | @property (assign) SEL requestDidFailSelector; 96 | @property (assign) SEL queueDidFinishSelector; 97 | @property (assign) BOOL shouldCancelAllRequestsOnFailure; 98 | @property (assign) id delegate; 99 | @property (assign) BOOL showAccurateProgress; 100 | @property (assign, readonly) int requestsCount; 101 | @property (retain) NSDictionary *userInfo; 102 | 103 | @property (assign) unsigned long long bytesUploadedSoFar; 104 | @property (assign) unsigned long long totalBytesToUpload; 105 | @property (assign) unsigned long long bytesDownloadedSoFar; 106 | @property (assign) unsigned long long totalBytesToDownload; 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesContainerRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesContainerRequest.m 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASICloudFilesContainerRequest.h" 8 | #import "ASICloudFilesContainer.h" 9 | #import "ASICloudFilesContainerXMLParserDelegate.h" 10 | 11 | 12 | @implementation ASICloudFilesContainerRequest 13 | 14 | @synthesize currentElement, currentContent, currentObject; 15 | @synthesize xmlParserDelegate; 16 | 17 | #pragma mark - 18 | #pragma mark Constructors 19 | 20 | + (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName queryString:(NSString *)queryString { 21 | NSString *urlString; 22 | if (containerName == nil) { 23 | urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest storageURL], queryString]; 24 | } else { 25 | urlString = [NSString stringWithFormat:@"%@/%@%@", [ASICloudFilesRequest storageURL], containerName, queryString]; 26 | } 27 | 28 | ASICloudFilesContainerRequest *request = [[[ASICloudFilesContainerRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease]; 29 | [request setRequestMethod:method]; 30 | [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 31 | return request; 32 | } 33 | 34 | + (id)storageRequestWithMethod:(NSString *)method queryString:(NSString *)queryString { 35 | return [ASICloudFilesContainerRequest storageRequestWithMethod:method containerName:nil queryString:queryString]; 36 | } 37 | 38 | + (id)storageRequestWithMethod:(NSString *)method { 39 | return [ASICloudFilesContainerRequest storageRequestWithMethod:method queryString:@""]; 40 | } 41 | 42 | #pragma mark - 43 | #pragma mark HEAD - Retrieve Container Count and Total Bytes Used 44 | 45 | // HEAD // 46 | // HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used. 47 | + (id)accountInfoRequest { 48 | ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"HEAD"]; 49 | return request; 50 | } 51 | 52 | - (NSUInteger)containerCount { 53 | return [[[self responseHeaders] objectForKey:@"X-Account-Container-Count"] intValue]; 54 | } 55 | 56 | - (NSUInteger)bytesUsed { 57 | return [[[self responseHeaders] objectForKey:@"X-Account-Bytes-Used"] intValue]; 58 | } 59 | 60 | #pragma mark - 61 | #pragma mark GET - Retrieve Container List 62 | 63 | + (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker { 64 | NSString *queryString = @"?format=xml"; 65 | 66 | if (limit > 0) { 67 | queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]]; 68 | } 69 | 70 | if (marker != nil) { 71 | queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]]; 72 | } 73 | 74 | ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET" queryString:queryString]; 75 | return request; 76 | } 77 | 78 | // GET /// 79 | // Create a request to list all containers 80 | + (id)listRequest { 81 | ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET" 82 | queryString:@"?format=xml"]; 83 | return request; 84 | } 85 | 86 | - (NSArray *)containers { 87 | if (xmlParserDelegate.containerObjects) { 88 | return xmlParserDelegate.containerObjects; 89 | } 90 | 91 | NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; 92 | if (xmlParserDelegate == nil) { 93 | xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init]; 94 | } 95 | 96 | [parser setDelegate:xmlParserDelegate]; 97 | [parser setShouldProcessNamespaces:NO]; 98 | [parser setShouldReportNamespacePrefixes:NO]; 99 | [parser setShouldResolveExternalEntities:NO]; 100 | [parser parse]; 101 | 102 | return xmlParserDelegate.containerObjects; 103 | } 104 | 105 | #pragma mark - 106 | #pragma mark PUT - Create Container 107 | 108 | // PUT /// 109 | + (id)createContainerRequest:(NSString *)containerName { 110 | ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"PUT" containerName:containerName queryString:@""]; 111 | return request; 112 | } 113 | 114 | #pragma mark - 115 | #pragma mark DELETE - Delete Container 116 | 117 | // DELETE /// 118 | + (id)deleteContainerRequest:(NSString *)containerName { 119 | ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"DELETE" containerName:containerName queryString:@""]; 120 | return request; 121 | } 122 | 123 | #pragma mark - 124 | #pragma mark Memory Management 125 | 126 | - (void)dealloc { 127 | [currentElement release]; 128 | [currentContent release]; 129 | [currentObject release]; 130 | [xmlParserDelegate release]; 131 | [super dealloc]; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /Classes/ASICacheDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICacheDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | @class ASIHTTPRequest; 11 | 12 | // Cache policies control the behaviour of a cache and how requests use the cache 13 | // When setting a cache policy, you can use a combination of these values as a bitmask 14 | // For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy]; 15 | // Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example. 16 | typedef enum _ASICachePolicy { 17 | 18 | // The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy 19 | // ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy' 20 | ASIUseDefaultCachePolicy = 0, 21 | 22 | // Tell the request not to read from the cache 23 | ASIDoNotReadFromCacheCachePolicy = 1, 24 | 25 | // The the request not to write to the cache 26 | ASIDoNotWriteToCacheCachePolicy = 2, 27 | 28 | // Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale 29 | ASIAskServerIfModifiedWhenStaleCachePolicy = 4, 30 | 31 | // Always ask the server if there is an updated version of this resource (using a conditional GET) 32 | ASIAskServerIfModifiedCachePolicy = 8, 33 | 34 | // If cached data exists, use it even if it is stale. This means requests will not talk to the server unless the resource they are requesting is not in the cache 35 | ASIOnlyLoadIfNotCachedCachePolicy = 16, 36 | 37 | // If cached data exists, use it even if it is stale. If cached data does not exist, stop (will not set an error on the request) 38 | ASIDontLoadCachePolicy = 32, 39 | 40 | // Specifies that cached data may be used if the request fails. If cached data is used, the request will succeed without error. Usually used in combination with other options above. 41 | ASIFallbackToCacheIfLoadFailsCachePolicy = 64 42 | } ASICachePolicy; 43 | 44 | // Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy) 45 | // Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy 46 | typedef enum _ASICacheStoragePolicy { 47 | ASICacheForSessionDurationCacheStoragePolicy = 0, 48 | ASICachePermanentlyCacheStoragePolicy = 1 49 | } ASICacheStoragePolicy; 50 | 51 | 52 | @protocol ASICacheDelegate 53 | 54 | @required 55 | 56 | // Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy 57 | - (ASICachePolicy)defaultCachePolicy; 58 | 59 | // Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date. 60 | - (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 61 | 62 | // Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date. 63 | - (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 64 | 65 | // Looks at the request's cache policy and any cached headers to determine if the cache data is still valid 66 | - (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request; 67 | 68 | // Removes cached data for a particular request 69 | - (void)removeCachedDataForRequest:(ASIHTTPRequest *)request; 70 | 71 | // Should return YES if the cache considers its cached response current for the request 72 | // Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired 73 | - (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request; 74 | 75 | // Should store the response for the passed request in the cache 76 | // When a non-zero maxAge is passed, it should be used as the expiry time for the cached response 77 | - (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 78 | 79 | // Removes cached data for a particular url 80 | - (void)removeCachedDataForURL:(NSURL *)url; 81 | 82 | // Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache 83 | - (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url; 84 | 85 | // Should return the cached body of a response for the passed URL, if it is stored in the cache 86 | - (NSData *)cachedResponseDataForURL:(NSURL *)url; 87 | 88 | // Returns a path to the cached response data, if it exists 89 | - (NSString *)pathToCachedResponseDataForURL:(NSURL *)url; 90 | 91 | // Returns a path to the cached response headers, if they url 92 | - (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url; 93 | 94 | // Returns the location to use to store cached response headers for a particular request 95 | - (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request; 96 | 97 | // Returns the location to use to store a cached response body for a particular request 98 | - (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request; 99 | 100 | // Clear cached data stored for the passed storage policy 101 | - (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /iPhone Sample/SynchronousViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SynchronousViewController.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "SynchronousViewController.h" 10 | #import "ASIHTTPRequest.h" 11 | #import "DetailCell.h" 12 | #import "InfoCell.h" 13 | 14 | @implementation SynchronousViewController 15 | 16 | 17 | // Runs a request synchronously 18 | - (IBAction)simpleURLFetch:(id)sender 19 | { 20 | NSURL *url = [NSURL URLWithString:[urlField text]]; 21 | 22 | // Create a request 23 | // You don't normally need to retain a synchronous request, but we need to in this case because we'll need it later if we reload the table data 24 | [self setRequest:[ASIHTTPRequest requestWithURL:url]]; 25 | 26 | //Customise our user agent, for no real reason 27 | [request addRequestHeader:@"User-Agent" value:@"ASIHTTPRequest"]; 28 | 29 | // Start the request 30 | [request startSynchronous]; 31 | 32 | // Request has now finished 33 | [[self tableView] reloadData]; 34 | 35 | } 36 | 37 | /* 38 | Most of the code below here relates to the table view, and isn't that interesting 39 | */ 40 | 41 | - (void)viewDidLoad 42 | { 43 | [super viewDidLoad]; 44 | [[[self navigationBar] topItem] setTitle:@"Synchronous Requests"]; 45 | 46 | } 47 | 48 | - (void)dealloc 49 | { 50 | [request cancel]; 51 | [request release]; 52 | [super dealloc]; 53 | } 54 | 55 | 56 | 57 | static NSString *intro = @"Demonstrates fetching a web page synchronously, the HTML source will appear in the box below when the download is complete. The interface will lock up when you press this button until the operation times out or succeeds. You should avoid using synchronous requests on the main thread, even for the simplest operations."; 58 | 59 | - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 60 | { 61 | int tablePadding = 40; 62 | int tableWidth = [tableView frame].size.width; 63 | if (tableWidth > 480) { // iPad 64 | tablePadding = 110; 65 | } 66 | 67 | UITableViewCell *cell; 68 | if ([indexPath section] == 0) { 69 | cell = [tableView dequeueReusableCellWithIdentifier:@"InfoCell"]; 70 | if (!cell) { 71 | cell = [InfoCell cell]; 72 | } 73 | [[cell textLabel] setText:intro]; 74 | [cell layoutSubviews]; 75 | 76 | } else if ([indexPath section] == 1) { 77 | cell = [tableView dequeueReusableCellWithIdentifier:@"URLCell"]; 78 | if (!cell) { 79 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"URLCell"] autorelease]; 80 | urlField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease]; 81 | [[cell contentView] addSubview:urlField]; 82 | goButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 83 | [goButton setTitle:@"Go!" forState:UIControlStateNormal]; 84 | [goButton addTarget:self action:@selector(simpleURLFetch:) forControlEvents:UIControlEventTouchUpInside]; 85 | [[cell contentView] addSubview:goButton]; 86 | } 87 | [goButton setFrame:CGRectMake(tableWidth-tablePadding-38,7,20,20)]; 88 | [goButton sizeToFit]; 89 | [urlField setFrame:CGRectMake(10,12,tableWidth-tablePadding-50,20)]; 90 | if ([self request]) { 91 | [urlField setText:[[[self request] url] absoluteString]]; 92 | } else { 93 | [urlField setText:@"http://allseeing-i.com"]; 94 | } 95 | 96 | 97 | } else if ([indexPath section] == 2) { 98 | cell = [tableView dequeueReusableCellWithIdentifier:@"ResponseCell"]; 99 | if (!cell) { 100 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ResponseCell"] autorelease]; 101 | responseField = [[[UITextView alloc] initWithFrame:CGRectZero] autorelease]; 102 | [responseField setBackgroundColor:[UIColor clearColor]]; 103 | [[cell contentView] addSubview:responseField]; 104 | } 105 | [responseField setFrame:CGRectMake(5,5,tableWidth-tablePadding,150)]; 106 | if (request) { 107 | if ([request error]) { 108 | [responseField setText:[[request error] localizedDescription]]; 109 | } else if ([request responseString]) { 110 | [responseField setText:[request responseString]]; 111 | } 112 | } 113 | 114 | } else { 115 | cell = [tableView dequeueReusableCellWithIdentifier:@"HeaderCell"]; 116 | if (!cell) { 117 | cell = [DetailCell cell]; 118 | } 119 | NSString *key = [[[request responseHeaders] allKeys] objectAtIndex:[indexPath row]]; 120 | [[cell textLabel] setText:key]; 121 | [[cell detailTextLabel] setText:[[request responseHeaders] objectForKey:key]]; 122 | } 123 | [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 124 | return cell; 125 | } 126 | 127 | - (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section 128 | { 129 | if (section == 3) { 130 | return [[request responseHeaders] count]; 131 | } else { 132 | return 1; 133 | } 134 | } 135 | 136 | - (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 137 | { 138 | if ([indexPath section] == 0) { 139 | return [InfoCell neededHeightForDescription:intro withTableWidth:[tableView frame].size.width]+20; 140 | } else if ([indexPath section] == 1) { 141 | return 48; 142 | } else if ([indexPath section] == 2) { 143 | return 160; 144 | } else { 145 | return 34; 146 | } 147 | } 148 | 149 | - (NSString *)tableView:(UITableView *)theTableView titleForHeaderInSection:(NSInteger)section 150 | { 151 | switch (section) { 152 | case 0: 153 | return nil; 154 | case 1: 155 | return @"Enter a URL"; 156 | case 2: 157 | return @"Response"; 158 | case 3: 159 | return @"Response Headers"; 160 | } 161 | return nil; 162 | } 163 | 164 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 165 | { 166 | if ([self request]) { 167 | return 4; 168 | } else { 169 | return 2; 170 | } 171 | } 172 | 173 | 174 | @synthesize request; 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3ObjectRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3ObjectRequest.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIS3ObjectRequest.h" 10 | 11 | NSString *const ASIS3StorageClassStandard = @"STANDARD"; 12 | NSString *const ASIS3StorageClassReducedRedundancy = @"REDUCED_REDUNDANCY"; 13 | 14 | @implementation ASIS3ObjectRequest 15 | 16 | - (ASIHTTPRequest *)HEADRequest 17 | { 18 | ASIS3ObjectRequest *headRequest = (ASIS3ObjectRequest *)[super HEADRequest]; 19 | [headRequest setKey:[self key]]; 20 | [headRequest setBucket:[self bucket]]; 21 | return headRequest; 22 | } 23 | 24 | + (id)requestWithBucket:(NSString *)theBucket key:(NSString *)theKey 25 | { 26 | ASIS3ObjectRequest *newRequest = [[[self alloc] initWithURL:nil] autorelease]; 27 | [newRequest setBucket:theBucket]; 28 | [newRequest setKey:theKey]; 29 | return newRequest; 30 | } 31 | 32 | + (id)requestWithBucket:(NSString *)theBucket key:(NSString *)theKey subResource:(NSString *)theSubResource 33 | { 34 | ASIS3ObjectRequest *newRequest = [[[self alloc] initWithURL:nil] autorelease]; 35 | [newRequest setSubResource:theSubResource]; 36 | [newRequest setBucket:theBucket]; 37 | [newRequest setKey:theKey]; 38 | return newRequest; 39 | } 40 | 41 | + (id)PUTRequestForData:(NSData *)data withBucket:(NSString *)theBucket key:(NSString *)theKey 42 | { 43 | ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey]; 44 | [newRequest appendPostData:data]; 45 | [newRequest setRequestMethod:@"PUT"]; 46 | return newRequest; 47 | } 48 | 49 | + (id)PUTRequestForFile:(NSString *)filePath withBucket:(NSString *)theBucket key:(NSString *)theKey 50 | { 51 | ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey]; 52 | [newRequest setPostBodyFilePath:filePath]; 53 | [newRequest setShouldStreamPostDataFromDisk:YES]; 54 | [newRequest setRequestMethod:@"PUT"]; 55 | [newRequest setMimeType:[ASIHTTPRequest mimeTypeForFileAtPath:filePath]]; 56 | return newRequest; 57 | } 58 | 59 | + (id)DELETERequestWithBucket:(NSString *)theBucket key:(NSString *)theKey 60 | { 61 | ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey]; 62 | [newRequest setRequestMethod:@"DELETE"]; 63 | return newRequest; 64 | } 65 | 66 | + (id)COPYRequestFromBucket:(NSString *)theSourceBucket key:(NSString *)theSourceKey toBucket:(NSString *)theBucket key:(NSString *)theKey 67 | { 68 | ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey]; 69 | [newRequest setRequestMethod:@"PUT"]; 70 | [newRequest setSourceBucket:theSourceBucket]; 71 | [newRequest setSourceKey:theSourceKey]; 72 | return newRequest; 73 | } 74 | 75 | + (id)HEADRequestWithBucket:(NSString *)theBucket key:(NSString *)theKey 76 | { 77 | ASIS3ObjectRequest *newRequest = [self requestWithBucket:theBucket key:theKey]; 78 | [newRequest setRequestMethod:@"HEAD"]; 79 | return newRequest; 80 | } 81 | 82 | - (id)copyWithZone:(NSZone *)zone 83 | { 84 | ASIS3ObjectRequest *newRequest = [super copyWithZone:zone]; 85 | [newRequest setBucket:[self bucket]]; 86 | [newRequest setKey:[self key]]; 87 | [newRequest setSourceBucket:[self sourceBucket]]; 88 | [newRequest setSourceKey:[self sourceKey]]; 89 | [newRequest setMimeType:[self mimeType]]; 90 | [newRequest setSubResource:[self subResource]]; 91 | [newRequest setStorageClass:[self storageClass]]; 92 | return newRequest; 93 | } 94 | 95 | - (void)dealloc 96 | { 97 | [bucket release]; 98 | [key release]; 99 | [mimeType release]; 100 | [sourceKey release]; 101 | [sourceBucket release]; 102 | [subResource release]; 103 | [storageClass release]; 104 | [super dealloc]; 105 | } 106 | 107 | - (void)buildURL 108 | { 109 | if ([self subResource]) { 110 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@?%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]],[self subResource]]]]; 111 | } else { 112 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]]]; 113 | } 114 | } 115 | 116 | - (NSString *)mimeType 117 | { 118 | if (mimeType) { 119 | return mimeType; 120 | } else if ([self postBodyFilePath]) { 121 | return [ASIHTTPRequest mimeTypeForFileAtPath:[self postBodyFilePath]]; 122 | } else { 123 | return @"application/octet-stream"; 124 | } 125 | } 126 | 127 | - (NSString *)canonicalizedResource 128 | { 129 | if ([[self subResource] length] > 0) { 130 | return [NSString stringWithFormat:@"/%@%@?%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]], [self subResource]]; 131 | } 132 | return [NSString stringWithFormat:@"/%@%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]; 133 | } 134 | 135 | - (NSMutableDictionary *)S3Headers 136 | { 137 | NSMutableDictionary *headers = [super S3Headers]; 138 | if ([self sourceKey]) { 139 | NSString *path = [ASIS3Request stringByURLEncodingForS3Path:[self sourceKey]]; 140 | [headers setObject:[[self sourceBucket] stringByAppendingString:path] forKey:@"x-amz-copy-source"]; 141 | } 142 | if ([self storageClass]) { 143 | [headers setObject:[self storageClass] forKey:@"x-amz-storage-class"]; 144 | } 145 | return headers; 146 | } 147 | 148 | - (NSString *)stringToSignForHeaders:(NSString *)canonicalizedAmzHeaders resource:(NSString *)canonicalizedResource 149 | { 150 | if ([[self requestMethod] isEqualToString:@"PUT"] && ![self sourceKey]) { 151 | [self addRequestHeader:@"Content-Type" value:[self mimeType]]; 152 | return [NSString stringWithFormat:@"PUT\n\n%@\n%@\n%@%@",[self mimeType],dateString,canonicalizedAmzHeaders,canonicalizedResource]; 153 | } 154 | return [super stringToSignForHeaders:canonicalizedAmzHeaders resource:canonicalizedResource]; 155 | } 156 | 157 | @synthesize bucket; 158 | @synthesize key; 159 | @synthesize sourceBucket; 160 | @synthesize sourceKey; 161 | @synthesize mimeType; 162 | @synthesize subResource; 163 | @synthesize storageClass; 164 | @end 165 | -------------------------------------------------------------------------------- /Classes/CloudFiles/ASICloudFilesCDNRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASICloudFilesCDNRequest.m 3 | // 4 | // Created by Michael Mayo on 1/6/10. 5 | // 6 | 7 | #import "ASICloudFilesCDNRequest.h" 8 | #import "ASICloudFilesContainerXMLParserDelegate.h" 9 | 10 | 11 | @implementation ASICloudFilesCDNRequest 12 | 13 | @synthesize accountName, containerName, xmlParserDelegate; 14 | 15 | + (id)cdnRequestWithMethod:(NSString *)method query:(NSString *)query { 16 | NSString *urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest cdnManagementURL], query]; 17 | ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease]; 18 | [request setRequestMethod:method]; 19 | [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 20 | return request; 21 | } 22 | 23 | + (id)cdnRequestWithMethod:(NSString *)method containerName:(NSString *)containerName { 24 | NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest cdnManagementURL], containerName]; 25 | ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease]; 26 | [request setRequestMethod:method]; 27 | [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 28 | request.containerName = containerName; 29 | return request; 30 | } 31 | 32 | #pragma mark - 33 | #pragma mark HEAD - Container Info 34 | 35 | + (id)containerInfoRequest:(NSString *)containerName { 36 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"HEAD" containerName:containerName]; 37 | return request; 38 | } 39 | 40 | - (BOOL)cdnEnabled { 41 | NSNumber *enabled = [[self responseHeaders] objectForKey:@"X-CDN-Enabled"]; 42 | if (!enabled) { 43 | enabled = [[self responseHeaders] objectForKey:@"X-Cdn-Enabled"]; 44 | } 45 | return [enabled boolValue]; 46 | } 47 | 48 | - (NSString *)cdnURI { 49 | NSString *uri = [[self responseHeaders] objectForKey:@"X-CDN-URI"]; 50 | if (!uri) { 51 | uri = [[self responseHeaders] objectForKey:@"X-Cdn-Uri"]; 52 | } 53 | return uri; 54 | } 55 | 56 | - (NSString *)cdnSSLURI { 57 | NSString *uri = [[self responseHeaders] objectForKey:@"X-CDN-SSL-URI"]; 58 | if (!uri) { 59 | uri = [[self responseHeaders] objectForKey:@"X-Cdn-Ssl-Uri"]; 60 | } 61 | return uri; 62 | } 63 | 64 | - (NSUInteger)cdnTTL { 65 | NSNumber *ttl = [[self responseHeaders] objectForKey:@"X-TTL"]; 66 | if (!ttl) { 67 | ttl = [[self responseHeaders] objectForKey:@"X-Ttl"]; 68 | } 69 | return [ttl intValue]; 70 | } 71 | 72 | #pragma mark - 73 | #pragma mark GET - CDN Container Lists 74 | 75 | + (id)listRequest { 76 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:@"?format=xml"]; 77 | return request; 78 | } 79 | 80 | + (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly { 81 | NSString *query = @"?format=xml"; 82 | 83 | if (limit > 0) { 84 | query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]]; 85 | } 86 | 87 | if (marker) { 88 | query = [query stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]]; 89 | } 90 | 91 | if (limit > 0) { 92 | query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]]; 93 | } 94 | 95 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:query]; 96 | return request; 97 | } 98 | 99 | - (NSArray *)containers { 100 | if (xmlParserDelegate.containerObjects) { 101 | return xmlParserDelegate.containerObjects; 102 | } 103 | 104 | NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; 105 | if (xmlParserDelegate == nil) { 106 | xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init]; 107 | } 108 | 109 | [parser setDelegate:xmlParserDelegate]; 110 | [parser setShouldProcessNamespaces:NO]; 111 | [parser setShouldReportNamespacePrefixes:NO]; 112 | [parser setShouldResolveExternalEntities:NO]; 113 | [parser parse]; 114 | 115 | return xmlParserDelegate.containerObjects; 116 | } 117 | 118 | #pragma mark - 119 | #pragma mark PUT - CDN Enable Container 120 | 121 | // PUT /// 122 | // PUT operations against a Container are used to CDN-enable that Container. 123 | // Include an HTTP header of X-TTL to specify a custom TTL. 124 | + (id)putRequestWithContainer:(NSString *)containerName { 125 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName]; 126 | return request; 127 | } 128 | 129 | + (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl { 130 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName]; 131 | [request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]]; 132 | return request; 133 | } 134 | 135 | #pragma mark - 136 | #pragma mark POST - Adjust CDN Attributes 137 | 138 | // POST /// 139 | // POST operations against a CDN-enabled Container are used to adjust CDN attributes. 140 | // The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN. 141 | // X-TTL: 86400 142 | // X-CDN-Enabled: True 143 | + (id)postRequestWithContainer:(NSString *)containerName { 144 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName]; 145 | return request; 146 | } 147 | 148 | + (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl { 149 | ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName]; 150 | if (ttl > 0) { 151 | [request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]]; 152 | } 153 | [request addRequestHeader:@"X-CDN-Enabled" value:cdnEnabled ? @"True" : @"False"]; 154 | return request; 155 | } 156 | 157 | #pragma mark - 158 | #pragma mark Memory Management 159 | 160 | -(void)dealloc { 161 | [accountName release]; 162 | [containerName release]; 163 | [xmlParserDelegate release]; 164 | [super dealloc]; 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /Classes/Tests/StressTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // StressTests.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 30/10/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | /* 10 | IMPORTANT 11 | All these tests depend on you running a local webserver on port 80 12 | These tests create 1000s of requests in a very short space of time - DO NOT RUN THESE TESTS ON A REMOTE WEBSERVER 13 | IMPORTANT 14 | */ 15 | 16 | #import "StressTests.h" 17 | #import "ASIHTTPRequest.h" 18 | #import "ASINetworkQueue.h" 19 | 20 | 21 | 22 | @implementation MyDelegate; 23 | - (void)dealloc 24 | { 25 | [request setDelegate:nil]; 26 | [request release]; 27 | [super dealloc]; 28 | } 29 | @synthesize request; 30 | @end 31 | 32 | // Stop clang complaining about undeclared selectors 33 | @interface StressTests () 34 | - (void)cancelRedirectRequest; 35 | - (void)cancelSetDelegateRequest; 36 | @end 37 | 38 | 39 | 40 | @implementation StressTests 41 | 42 | // A test for a potential crasher that used to exist when requests were cancelled 43 | // We aren't testing a specific condition here, but rather attempting to trigger a crash 44 | - (void)testCancelQueue 45 | { 46 | ASINetworkQueue *queue = [ASINetworkQueue queue]; 47 | 48 | // Increase the risk of this crash 49 | [queue setMaxConcurrentOperationCount:25]; 50 | int i; 51 | for (i=0; i<100; i++) { 52 | ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1"]]; 53 | [queue addOperation:request]; 54 | } 55 | [queue go]; 56 | [queue cancelAllOperations]; 57 | 58 | // Run the test again with requests running on a background thread 59 | queue = [ASINetworkQueue queue]; 60 | 61 | [queue setMaxConcurrentOperationCount:25]; 62 | for (i=0; i<100; i++) { 63 | ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1"]]; 64 | [queue addOperation:request]; 65 | } 66 | [queue go]; 67 | [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; 68 | [queue cancelAllOperations]; 69 | 70 | } 71 | 72 | // This test looks for thread-safety problems with cancelling requests 73 | // It will run for 30 seconds, creating a request, then cancelling it and creating another as soon as it gets some indication of progress 74 | 75 | - (void)testCancelStressTest 76 | { 77 | [self setCancelStartDate:[NSDate dateWithTimeIntervalSinceNow:30]]; 78 | [self performCancelRequest]; 79 | while ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 80 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; 81 | } 82 | NSLog(@"Stress test: DONE"); 83 | } 84 | 85 | - (void)performCancelRequest 86 | { 87 | [self setCancelRequest:[ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/ASIHTTPRequest/tests/the_great_american_novel.txt"]]]; 88 | if ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 89 | [[self cancelRequest] setDownloadProgressDelegate:self]; 90 | [[self cancelRequest] setShowAccurateProgress:YES]; 91 | NSLog(@"Stress test: Start request %@",[self cancelRequest]); 92 | [[self cancelRequest] startAsynchronous]; 93 | } 94 | } 95 | 96 | 97 | // Another stress test that looks from problems when redirecting 98 | 99 | - (void)testRedirectStressTest 100 | { 101 | [self setCancelStartDate:[NSDate dateWithTimeIntervalSinceNow:30]]; 102 | [self performRedirectRequest]; 103 | while ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 104 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; 105 | } 106 | NSLog(@"Redirect stress test: DONE"); 107 | } 108 | 109 | - (void)performRedirectRequest 110 | { 111 | [self setCancelRequest:[ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/ASIHTTPRequest/tests/one_infinite_loop"]]]; 112 | if ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 113 | NSLog(@"Redirect stress test: Start request %@",[self cancelRequest]); 114 | [[self cancelRequest] startAsynchronous]; 115 | [self performSelector:@selector(cancelRedirectRequest) withObject:nil afterDelay:0.2]; 116 | } 117 | } 118 | 119 | - (void)cancelRedirectRequest 120 | { 121 | NSLog(@"Redirect stress test: Cancel request %@",[self cancelRequest]); 122 | [[self cancelRequest] cancel]; 123 | [self performRedirectRequest]; 124 | } 125 | 126 | // Ensures we can set the delegate while the request is running without problems 127 | - (void)testSetDelegate 128 | { 129 | [self setCreateRequestLock:[[[NSLock alloc] init] autorelease]]; 130 | [self setCancelStartDate:[NSDate dateWithTimeIntervalSinceNow:30]]; 131 | [self performSetDelegateRequest]; 132 | while ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 133 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; 134 | } 135 | NSLog(@"Set delegate stress test: DONE"); 136 | } 137 | 138 | - (void)performSetDelegateRequest 139 | { 140 | [self setDelegate:nil]; 141 | 142 | [createRequestLock lock]; 143 | [self setCancelRequest:[ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/ASIHTTPRequest/tests/the_great_american_novel.txt"]]]; 144 | if ([[self cancelStartDate] timeIntervalSinceNow] > 0) { 145 | [self setDelegate:[[[MyDelegate alloc] init] autorelease]]; 146 | [[self delegate] setRequest:[self cancelRequest]]; 147 | [[self cancelRequest] setDelegate:delegate]; 148 | [[self cancelRequest] setShowAccurateProgress:YES]; 149 | NSLog(@"Set delegate stress test: Start request %@",[self cancelRequest]); 150 | [[self cancelRequest] startAsynchronous]; 151 | [self performSelectorInBackground:@selector(cancelSetDelegateRequest) withObject:nil]; 152 | } 153 | [createRequestLock unlock]; 154 | } 155 | 156 | - (void)cancelSetDelegateRequest 157 | { 158 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 159 | [self performSetDelegateRequest]; 160 | [pool release]; 161 | } 162 | 163 | 164 | - (void)setDoubleValue:(double)newProgress 165 | { 166 | [self setProgress:(float)newProgress]; 167 | } 168 | 169 | - (void)setProgress:(float)newProgress 170 | { 171 | progress = newProgress; 172 | 173 | // For cancel test 174 | if (newProgress > 0 && [self cancelRequest]) { 175 | 176 | NSLog(@"Stress test: Cancel request %@",[self cancelRequest]); 177 | [[self cancelRequest] cancel]; 178 | 179 | [self performSelector:@selector(performCancelRequest) withObject:nil afterDelay:0.2]; 180 | [self setCancelRequest:nil]; 181 | } 182 | } 183 | 184 | 185 | 186 | 187 | 188 | @synthesize cancelRequest; 189 | @synthesize cancelStartDate; 190 | @synthesize delegate; 191 | @synthesize createRequestLock; 192 | @end 193 | -------------------------------------------------------------------------------- /Classes/S3/ASIS3BucketRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIS3BucketRequest.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 16/03/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIS3BucketRequest.h" 10 | #import "ASIS3BucketObject.h" 11 | 12 | 13 | // Private stuff 14 | @interface ASIS3BucketRequest () 15 | @property (retain, nonatomic) ASIS3BucketObject *currentObject; 16 | @property (retain) NSMutableArray *objects; 17 | @property (retain) NSMutableArray *commonPrefixes; 18 | @property (assign) BOOL isTruncated; 19 | @end 20 | 21 | @implementation ASIS3BucketRequest 22 | 23 | - (id)initWithURL:(NSURL *)newURL 24 | { 25 | self = [super initWithURL:newURL]; 26 | [self setObjects:[[[NSMutableArray alloc] init] autorelease]]; 27 | [self setCommonPrefixes:[[[NSMutableArray alloc] init] autorelease]]; 28 | return self; 29 | } 30 | 31 | + (id)requestWithBucket:(NSString *)theBucket 32 | { 33 | ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease]; 34 | [request setBucket:theBucket]; 35 | return request; 36 | } 37 | 38 | + (id)requestWithBucket:(NSString *)theBucket subResource:(NSString *)theSubResource 39 | { 40 | ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease]; 41 | [request setBucket:theBucket]; 42 | [request setSubResource:theSubResource]; 43 | return request; 44 | } 45 | 46 | + (id)PUTRequestWithBucket:(NSString *)theBucket 47 | { 48 | ASIS3BucketRequest *request = [self requestWithBucket:theBucket]; 49 | [request setRequestMethod:@"PUT"]; 50 | return request; 51 | } 52 | 53 | 54 | + (id)DELETERequestWithBucket:(NSString *)theBucket 55 | { 56 | ASIS3BucketRequest *request = [self requestWithBucket:theBucket]; 57 | [request setRequestMethod:@"DELETE"]; 58 | return request; 59 | } 60 | 61 | - (void)dealloc 62 | { 63 | [currentObject release]; 64 | [objects release]; 65 | [commonPrefixes release]; 66 | [prefix release]; 67 | [marker release]; 68 | [delimiter release]; 69 | [subResource release]; 70 | [bucket release]; 71 | [super dealloc]; 72 | } 73 | 74 | - (NSString *)canonicalizedResource 75 | { 76 | if ([self subResource]) { 77 | return [NSString stringWithFormat:@"/%@/?%@",[self bucket],[self subResource]]; 78 | } 79 | return [NSString stringWithFormat:@"/%@/",[self bucket]]; 80 | } 81 | 82 | - (void)buildURL 83 | { 84 | NSString *baseURL; 85 | if ([self subResource]) { 86 | baseURL = [NSString stringWithFormat:@"%@://%@.%@/?%@",[self requestScheme],[self bucket],[[self class] S3Host],[self subResource]]; 87 | } else { 88 | baseURL = [NSString stringWithFormat:@"%@://%@.%@",[self requestScheme],[self bucket],[[self class] S3Host]]; 89 | } 90 | NSMutableArray *queryParts = [[[NSMutableArray alloc] init] autorelease]; 91 | if ([self prefix]) { 92 | [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; 93 | } 94 | if ([self marker]) { 95 | [queryParts addObject:[NSString stringWithFormat:@"marker=%@",[[self marker] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; 96 | } 97 | if ([self delimiter]) { 98 | [queryParts addObject:[NSString stringWithFormat:@"delimiter=%@",[[self delimiter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; 99 | } 100 | if ([self maxResultCount] > 0) { 101 | [queryParts addObject:[NSString stringWithFormat:@"max-keys=%hi",[self maxResultCount]]]; 102 | } 103 | if ([queryParts count]) { 104 | NSString* template = @"%@?%@"; 105 | if ([[self subResource] length] > 0) { 106 | template = @"%@&%@"; 107 | } 108 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,baseURL,[queryParts componentsJoinedByString:@"&"]]]]; 109 | } else { 110 | [self setURL:[NSURL URLWithString:baseURL]]; 111 | 112 | } 113 | } 114 | 115 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 116 | { 117 | if ([elementName isEqualToString:@"Contents"]) { 118 | [self setCurrentObject:[ASIS3BucketObject objectWithBucket:[self bucket]]]; 119 | } 120 | [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict]; 121 | } 122 | 123 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 124 | { 125 | if ([elementName isEqualToString:@"Contents"]) { 126 | [objects addObject:currentObject]; 127 | [self setCurrentObject:nil]; 128 | } else if ([elementName isEqualToString:@"Key"]) { 129 | [[self currentObject] setKey:[self currentXMLElementContent]]; 130 | } else if ([elementName isEqualToString:@"LastModified"]) { 131 | [[self currentObject] setLastModified:[[ASIS3Request S3ResponseDateFormatter] dateFromString:[self currentXMLElementContent]]]; 132 | } else if ([elementName isEqualToString:@"ETag"]) { 133 | [[self currentObject] setETag:[self currentXMLElementContent]]; 134 | } else if ([elementName isEqualToString:@"Size"]) { 135 | [[self currentObject] setSize:(unsigned long long)[[self currentXMLElementContent] longLongValue]]; 136 | } else if ([elementName isEqualToString:@"ID"]) { 137 | [[self currentObject] setOwnerID:[self currentXMLElementContent]]; 138 | } else if ([elementName isEqualToString:@"DisplayName"]) { 139 | [[self currentObject] setOwnerName:[self currentXMLElementContent]]; 140 | } else if ([elementName isEqualToString:@"Prefix"] && [[self currentXMLElementStack] count] > 2 && [[[self currentXMLElementStack] objectAtIndex:[[self currentXMLElementStack] count]-2] isEqualToString:@"CommonPrefixes"]) { 141 | [[self commonPrefixes] addObject:[self currentXMLElementContent]]; 142 | } else if ([elementName isEqualToString:@"IsTruncated"]) { 143 | [self setIsTruncated:[[self currentXMLElementContent] isEqualToString:@"true"]]; 144 | } else { 145 | // Let ASIS3Request look for error messages 146 | [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 147 | } 148 | } 149 | 150 | #pragma mark NSCopying 151 | 152 | - (id)copyWithZone:(NSZone *)zone 153 | { 154 | ASIS3BucketRequest *newRequest = [super copyWithZone:zone]; 155 | [newRequest setBucket:[self bucket]]; 156 | [newRequest setSubResource:[self subResource]]; 157 | [newRequest setPrefix:[self prefix]]; 158 | [newRequest setMarker:[self marker]]; 159 | [newRequest setMaxResultCount:[self maxResultCount]]; 160 | [newRequest setDelimiter:[self delimiter]]; 161 | return newRequest; 162 | } 163 | 164 | @synthesize bucket; 165 | @synthesize subResource; 166 | @synthesize currentObject; 167 | @synthesize objects; 168 | @synthesize commonPrefixes; 169 | @synthesize prefix; 170 | @synthesize marker; 171 | @synthesize maxResultCount; 172 | @synthesize delimiter; 173 | @synthesize isTruncated; 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /Classes/ASIDataDecompressor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataDecompressor.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIDataDecompressor.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | #define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks 13 | 14 | @interface ASIDataDecompressor () 15 | + (NSError *)inflateErrorWithCode:(int)code; 16 | @end; 17 | 18 | @implementation ASIDataDecompressor 19 | 20 | + (id)decompressor 21 | { 22 | ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease]; 23 | [decompressor setupStream]; 24 | return decompressor; 25 | } 26 | 27 | - (void)dealloc 28 | { 29 | if (streamReady) { 30 | [self closeStream]; 31 | } 32 | [super dealloc]; 33 | } 34 | 35 | - (NSError *)setupStream 36 | { 37 | if (streamReady) { 38 | return nil; 39 | } 40 | // Setup the inflate stream 41 | zStream.zalloc = Z_NULL; 42 | zStream.zfree = Z_NULL; 43 | zStream.opaque = Z_NULL; 44 | zStream.avail_in = 0; 45 | zStream.next_in = 0; 46 | int status = inflateInit2(&zStream, (15+32)); 47 | if (status != Z_OK) { 48 | return [[self class] inflateErrorWithCode:status]; 49 | } 50 | streamReady = YES; 51 | return nil; 52 | } 53 | 54 | - (NSError *)closeStream 55 | { 56 | if (!streamReady) { 57 | return nil; 58 | } 59 | // Close the inflate stream 60 | streamReady = NO; 61 | int status = inflateEnd(&zStream); 62 | if (status != Z_OK) { 63 | return [[self class] inflateErrorWithCode:status]; 64 | } 65 | return nil; 66 | } 67 | 68 | - (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err 69 | { 70 | if (length == 0) return nil; 71 | 72 | NSUInteger halfLength = length/2; 73 | NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength]; 74 | 75 | int status; 76 | 77 | zStream.next_in = bytes; 78 | zStream.avail_in = (unsigned int)length; 79 | zStream.avail_out = 0; 80 | 81 | NSInteger bytesProcessedAlready = zStream.total_out; 82 | while (zStream.avail_in != 0) { 83 | 84 | if (zStream.total_out-bytesProcessedAlready >= [outputData length]) { 85 | [outputData increaseLengthBy:halfLength]; 86 | } 87 | 88 | zStream.next_out = [outputData mutableBytes] + zStream.total_out-bytesProcessedAlready; 89 | zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready)); 90 | 91 | status = inflate(&zStream, Z_NO_FLUSH); 92 | 93 | if (status == Z_STREAM_END) { 94 | break; 95 | } else if (status != Z_OK) { 96 | if (err) { 97 | *err = [[self class] inflateErrorWithCode:status]; 98 | } 99 | return nil; 100 | } 101 | } 102 | 103 | // Set real length 104 | [outputData setLength: zStream.total_out-bytesProcessedAlready]; 105 | return outputData; 106 | } 107 | 108 | 109 | + (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err 110 | { 111 | NSError *theError = nil; 112 | NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError]; 113 | if (theError) { 114 | if (err) { 115 | *err = theError; 116 | } 117 | return nil; 118 | } 119 | return outputData; 120 | } 121 | 122 | + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err 123 | { 124 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 125 | 126 | // Create an empty file at the destination path 127 | if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) { 128 | if (err) { 129 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]]; 130 | } 131 | return NO; 132 | } 133 | 134 | // Ensure the source file exists 135 | if (![fileManager fileExistsAtPath:sourcePath]) { 136 | if (err) { 137 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]]; 138 | } 139 | return NO; 140 | } 141 | 142 | UInt8 inputData[DATA_CHUNK_SIZE]; 143 | NSData *outputData; 144 | NSInteger readLength; 145 | NSError *theError = nil; 146 | 147 | 148 | ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor]; 149 | 150 | NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath]; 151 | [inputStream open]; 152 | NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO]; 153 | [outputStream open]; 154 | 155 | while ([decompressor streamReady]) { 156 | 157 | // Read some data from the file 158 | readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE]; 159 | 160 | // Make sure nothing went wrong 161 | if ([inputStream streamStatus] == NSStreamEventErrorOccurred) { 162 | if (err) { 163 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]]; 164 | } 165 | [decompressor closeStream]; 166 | return NO; 167 | } 168 | // Have we reached the end of the input data? 169 | if (!readLength) { 170 | break; 171 | } 172 | 173 | // Attempt to inflate the chunk of data 174 | outputData = [decompressor uncompressBytes:inputData length:readLength error:&theError]; 175 | if (theError) { 176 | if (err) { 177 | *err = theError; 178 | } 179 | [decompressor closeStream]; 180 | return NO; 181 | } 182 | 183 | // Write the inflated data out to the destination file 184 | [outputStream write:[outputData bytes] maxLength:[outputData length]]; 185 | 186 | // Make sure nothing went wrong 187 | if ([inputStream streamStatus] == NSStreamEventErrorOccurred) { 188 | if (err) { 189 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at &@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]]; 190 | } 191 | [decompressor closeStream]; 192 | return NO; 193 | } 194 | 195 | } 196 | 197 | [inputStream close]; 198 | [outputStream close]; 199 | 200 | NSError *error = [decompressor closeStream]; 201 | if (error) { 202 | if (err) { 203 | *err = error; 204 | } 205 | return NO; 206 | } 207 | 208 | return YES; 209 | } 210 | 211 | 212 | + (NSError *)inflateErrorWithCode:(int)code 213 | { 214 | return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]]; 215 | } 216 | 217 | @synthesize streamReady; 218 | @end 219 | -------------------------------------------------------------------------------- /iPhone Sample/UploadViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // UploadViewController.m 3 | // Part of the ASIHTTPRequest sample project - see http://allseeing-i.com/ASIHTTPRequest for details 4 | // 5 | // Created by Ben Copsey on 31/12/2008. 6 | // Copyright 2008 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "UploadViewController.h" 10 | #import "ASIFormDataRequest.h" 11 | #import "InfoCell.h" 12 | 13 | // Private stuff 14 | @interface UploadViewController () 15 | - (void)uploadFailed:(ASIHTTPRequest *)theRequest; 16 | - (void)uploadFinished:(ASIHTTPRequest *)theRequest; 17 | @end 18 | 19 | @implementation UploadViewController 20 | 21 | - (IBAction)performLargeUpload:(id)sender 22 | { 23 | [request cancel]; 24 | [self setRequest:[ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]]]; 25 | [request setPostValue:@"test" forKey:@"value1"]; 26 | [request setPostValue:@"test" forKey:@"value2"]; 27 | [request setPostValue:@"test" forKey:@"value3"]; 28 | [request setTimeOutSeconds:20]; 29 | 30 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 31 | [request setShouldContinueWhenAppEntersBackground:YES]; 32 | #endif 33 | [request setUploadProgressDelegate:progressIndicator]; 34 | [request setDelegate:self]; 35 | [request setDidFailSelector:@selector(uploadFailed:)]; 36 | [request setDidFinishSelector:@selector(uploadFinished:)]; 37 | 38 | //Create a 256KB file 39 | NSData *data = [[[NSMutableData alloc] initWithLength:256*1024] autorelease]; 40 | NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"file"]; 41 | [data writeToFile:path atomically:NO]; 42 | 43 | //Add the file 8 times to the request, for a total request size around 2MB 44 | int i; 45 | for (i=0; i<8; i++) { 46 | [request setFile:path forKey:[NSString stringWithFormat:@"file-%hi",i]]; 47 | } 48 | 49 | [request startAsynchronous]; 50 | [resultView setText:@"Uploading data..."]; 51 | } 52 | 53 | - (IBAction)toggleThrottling:(id)sender 54 | { 55 | [ASIHTTPRequest setShouldThrottleBandwidthForWWAN:[(UISwitch *)sender isOn]]; 56 | } 57 | 58 | - (void)uploadFailed:(ASIHTTPRequest *)theRequest 59 | { 60 | [resultView setText:[NSString stringWithFormat:@"Request failed:\r\n%@",[[theRequest error] localizedDescription]]]; 61 | } 62 | 63 | - (void)uploadFinished:(ASIHTTPRequest *)theRequest 64 | { 65 | [resultView setText:[NSString stringWithFormat:@"Finished uploading %llu bytes of data",[theRequest postLength]]]; 66 | 67 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 68 | // Clear out the old notification before scheduling a new one. 69 | if ([[[UIApplication sharedApplication] scheduledLocalNotifications] count] > 0) 70 | [[UIApplication sharedApplication] cancelAllLocalNotifications]; 71 | 72 | // Create a new notification 73 | UILocalNotification *notification = [[[UILocalNotification alloc] init] autorelease]; 74 | if (notification) { 75 | [notification setFireDate:[NSDate date]]; 76 | [notification setTimeZone:[NSTimeZone defaultTimeZone]]; 77 | [notification setRepeatInterval:0]; 78 | [notification setSoundName:@"alarmsound.caf"]; 79 | [notification setAlertBody:@"Boom!\r\n\r\nUpload is finished!"]; 80 | [[UIApplication sharedApplication] scheduleLocalNotification:notification]; 81 | } 82 | #endif 83 | } 84 | 85 | - (void)dealloc 86 | { 87 | [request setDelegate:nil]; 88 | [request setUploadProgressDelegate:nil]; 89 | [request cancel]; 90 | [request release]; 91 | [progressIndicator release]; 92 | [resultView release]; 93 | [super dealloc]; 94 | } 95 | 96 | /* 97 | Most of the code below here relates to the table view, and isn't that interesting 98 | */ 99 | 100 | - (void)viewDidLoad 101 | { 102 | [super viewDidLoad]; 103 | [[[self navigationBar] topItem] setTitle:@"Tracking Upload Progress"]; 104 | resultView = [[UITextView alloc] initWithFrame:CGRectZero]; 105 | [resultView setBackgroundColor:[UIColor clearColor]]; 106 | progressIndicator = [[UIProgressView alloc] initWithFrame:CGRectZero]; 107 | } 108 | 109 | static NSString *intro = @"Demonstrates POSTing content to a URL, showing upload progress.\nYou'll only see accurate progress for uploads when the request body is larger than 128KB (in 2.2.1 SDK), or when the request body is larger than 32KB (in 3.0 SDK)\n\nThis request is also setup to run when the app enters the background on devices running on iOS4. In the delegate method that is called when the request finishes, we show a local notification to let the user know the upload is finished."; 110 | 111 | - (UIView *)tableView:(UITableView *)theTableView viewForHeaderInSection:(NSInteger)section 112 | { 113 | if (section == 1) { 114 | int tablePadding = 40; 115 | int tableWidth = [tableView frame].size.width; 116 | if (tableWidth > 480) { // iPad 117 | tablePadding = 110; 118 | } 119 | 120 | UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0,0,tableWidth-(tablePadding/2),30)] autorelease]; 121 | UIButton *goButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 122 | [goButton setTitle:@"Go!" forState:UIControlStateNormal]; 123 | [goButton sizeToFit]; 124 | [goButton setFrame:CGRectMake([view frame].size.width-[goButton frame].size.width+10,7,[goButton frame].size.width,[goButton frame].size.height)]; 125 | 126 | [goButton addTarget:self action:@selector(performLargeUpload:) forControlEvents:UIControlEventTouchUpInside]; 127 | [view addSubview:goButton]; 128 | [progressIndicator setFrame:CGRectMake((tablePadding/2)-10,20,200,10)]; 129 | [view addSubview:progressIndicator]; 130 | 131 | return view; 132 | } 133 | return nil; 134 | } 135 | 136 | - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 137 | { 138 | int tablePadding = 40; 139 | int tableWidth = [tableView frame].size.width; 140 | if (tableWidth > 480) { // iPad 141 | tablePadding = 110; 142 | } 143 | 144 | UITableViewCell *cell; 145 | if ([indexPath section] == 0) { 146 | cell = [tableView dequeueReusableCellWithIdentifier:@"InfoCell"]; 147 | if (!cell) { 148 | cell = [InfoCell cell]; 149 | } 150 | [[cell textLabel] setText:intro]; 151 | [cell layoutSubviews]; 152 | 153 | 154 | } else if ([indexPath section] == 1) { 155 | return nil; 156 | } else { 157 | cell = [tableView dequeueReusableCellWithIdentifier:@"Response"]; 158 | if (!cell) { 159 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Response"] autorelease]; 160 | [[cell contentView] addSubview:resultView]; 161 | } 162 | [resultView setFrame:CGRectMake(5,5,tableWidth-tablePadding,60)]; 163 | } 164 | [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 165 | 166 | return cell; 167 | } 168 | 169 | - (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section 170 | { 171 | if (section == 1) { 172 | return 0; 173 | } 174 | return 1; 175 | } 176 | 177 | - (CGFloat)tableView:(UITableView *)theTableView heightForHeaderInSection:(NSInteger)section 178 | { 179 | if (section == 1) { 180 | return 50; 181 | } 182 | return 34; 183 | } 184 | 185 | - (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 186 | { 187 | if ([indexPath section] == 0) { 188 | return [InfoCell neededHeightForDescription:intro withTableWidth:[tableView frame].size.width]+20; 189 | } else if ([indexPath section] == 2) { 190 | return 80; 191 | } else { 192 | return 42; 193 | } 194 | } 195 | 196 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 197 | { 198 | return 3; 199 | } 200 | 201 | @synthesize request; 202 | @end 203 | -------------------------------------------------------------------------------- /Classes/ASIDataCompressor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressor.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIDataCompressor.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | #define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks 13 | #define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION 14 | 15 | @interface ASIDataCompressor () 16 | + (NSError *)deflateErrorWithCode:(int)code; 17 | @end 18 | 19 | @implementation ASIDataCompressor 20 | 21 | + (id)compressor 22 | { 23 | ASIDataCompressor *compressor = [[[self alloc] init] autorelease]; 24 | [compressor setupStream]; 25 | return compressor; 26 | } 27 | 28 | - (void)dealloc 29 | { 30 | if (streamReady) { 31 | [self closeStream]; 32 | } 33 | [super dealloc]; 34 | } 35 | 36 | - (NSError *)setupStream 37 | { 38 | if (streamReady) { 39 | return nil; 40 | } 41 | // Setup the inflate stream 42 | zStream.zalloc = Z_NULL; 43 | zStream.zfree = Z_NULL; 44 | zStream.opaque = Z_NULL; 45 | zStream.avail_in = 0; 46 | zStream.next_in = 0; 47 | int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY); 48 | if (status != Z_OK) { 49 | return [[self class] deflateErrorWithCode:status]; 50 | } 51 | streamReady = YES; 52 | return nil; 53 | } 54 | 55 | - (NSError *)closeStream 56 | { 57 | if (!streamReady) { 58 | return nil; 59 | } 60 | // Close the deflate stream 61 | streamReady = NO; 62 | int status = deflateEnd(&zStream); 63 | if (status != Z_OK) { 64 | return [[self class] deflateErrorWithCode:status]; 65 | } 66 | return nil; 67 | } 68 | 69 | - (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish 70 | { 71 | if (length == 0) return nil; 72 | 73 | NSUInteger halfLength = length/2; 74 | 75 | // We'll take a guess that the compressed data will fit in half the size of the original (ie the max to compress at once is half DATA_CHUNK_SIZE), if not, we'll increase it below 76 | NSMutableData *outputData = [NSMutableData dataWithLength:length/2]; 77 | 78 | int status; 79 | 80 | zStream.next_in = bytes; 81 | zStream.avail_in = (unsigned int)length; 82 | zStream.avail_out = 0; 83 | 84 | NSInteger bytesProcessedAlready = zStream.total_out; 85 | while (zStream.avail_out == 0) { 86 | 87 | if (zStream.total_out-bytesProcessedAlready >= [outputData length]) { 88 | [outputData increaseLengthBy:halfLength]; 89 | } 90 | 91 | zStream.next_out = [outputData mutableBytes] + zStream.total_out-bytesProcessedAlready; 92 | zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready)); 93 | status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH); 94 | 95 | if (status == Z_STREAM_END) { 96 | break; 97 | } else if (status != Z_OK) { 98 | if (err) { 99 | *err = [[self class] deflateErrorWithCode:status]; 100 | } 101 | return NO; 102 | } 103 | } 104 | 105 | // Set real length 106 | [outputData setLength: zStream.total_out-bytesProcessedAlready]; 107 | return outputData; 108 | } 109 | 110 | 111 | + (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err 112 | { 113 | NSError *theError = nil; 114 | NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES]; 115 | if (theError) { 116 | if (err) { 117 | *err = theError; 118 | } 119 | return nil; 120 | } 121 | return outputData; 122 | } 123 | 124 | 125 | 126 | + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err 127 | { 128 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 129 | 130 | // Create an empty file at the destination path 131 | if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) { 132 | if (err) { 133 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]]; 134 | } 135 | return NO; 136 | } 137 | 138 | // Ensure the source file exists 139 | if (![fileManager fileExistsAtPath:sourcePath]) { 140 | if (err) { 141 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]]; 142 | } 143 | return NO; 144 | } 145 | 146 | UInt8 inputData[DATA_CHUNK_SIZE]; 147 | NSData *outputData; 148 | NSInteger readLength; 149 | NSError *theError = nil; 150 | 151 | ASIDataCompressor *compressor = [ASIDataCompressor compressor]; 152 | 153 | NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath]; 154 | [inputStream open]; 155 | NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO]; 156 | [outputStream open]; 157 | 158 | while ([compressor streamReady]) { 159 | 160 | // Read some data from the file 161 | readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE]; 162 | 163 | // Make sure nothing went wrong 164 | if ([inputStream streamStatus] == NSStreamEventErrorOccurred) { 165 | if (err) { 166 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]]; 167 | } 168 | [compressor closeStream]; 169 | return NO; 170 | } 171 | // Have we reached the end of the input data? 172 | if (!readLength) { 173 | break; 174 | } 175 | 176 | // Attempt to deflate the chunk of data 177 | outputData = [compressor compressBytes:inputData length:readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE ]; 178 | if (theError) { 179 | if (err) { 180 | *err = theError; 181 | } 182 | [compressor closeStream]; 183 | return NO; 184 | } 185 | 186 | // Write the deflated data out to the destination file 187 | [outputStream write:[outputData bytes] maxLength:[outputData length]]; 188 | 189 | // Make sure nothing went wrong 190 | if ([inputStream streamStatus] == NSStreamEventErrorOccurred) { 191 | if (err) { 192 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at &@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]]; 193 | } 194 | [compressor closeStream]; 195 | return NO; 196 | } 197 | 198 | } 199 | [inputStream close]; 200 | [outputStream close]; 201 | 202 | NSError *error = [compressor closeStream]; 203 | if (error) { 204 | if (err) { 205 | *err = error; 206 | } 207 | return NO; 208 | } 209 | 210 | return YES; 211 | } 212 | 213 | + (NSError *)deflateErrorWithCode:(int)code 214 | { 215 | return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]]; 216 | } 217 | 218 | @synthesize streamReady; 219 | @end 220 | -------------------------------------------------------------------------------- /Classes/Tests/ASIDataCompressorTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressorTests.m 3 | // Mac 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | // Sadly these tests only work on Mac because of the dependency on NSTask, but I'm fairly sure this class should behave in the same way on iOS 9 | 10 | #import "ASIDataCompressorTests.h" 11 | #import "ASIDataCompressor.h" 12 | #import "ASIDataDecompressor.h" 13 | #import "ASIHTTPRequest.h" 14 | 15 | @implementation ASIDataCompressorTests 16 | 17 | - (void)setUp 18 | { 19 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 20 | 21 | // Download a 1.7MB text file 22 | NSString *filePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"story.txt"]; 23 | if (![fileManager fileExistsAtPath:filePath] || [[[fileManager attributesOfItemAtPath:filePath error:NULL] objectForKey:NSFileSize] unsignedLongLongValue] < 1693961) { 24 | ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_hound_of_the_baskervilles.text"]]; 25 | [request setDownloadDestinationPath:[[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"story.txt"]]; 26 | [request startSynchronous]; 27 | } 28 | } 29 | 30 | - (void)testInflateData 31 | { 32 | 33 | NSString *originalString = [NSString stringWithContentsOfFile:[[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"story.txt"] encoding:NSUTF8StringEncoding error:NULL]; 34 | 35 | // Test in-memory inflate using uncompressData:error: 36 | NSError *error = nil; 37 | NSString *filePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"uncompressed_file.txt"]; 38 | NSString *gzippedFilePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"uncompressed_file.txt.gz"]; 39 | [ASIHTTPRequest removeFileAtPath:gzippedFilePath error:&error]; 40 | if (error) { 41 | GHFail(@"Failed to remove old file, cannot proceed with test"); 42 | } 43 | [originalString writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:&error]; 44 | if (error) { 45 | GHFail(@"Failed to write string, cannot proceed with test"); 46 | } 47 | 48 | NSTask *task = [[[NSTask alloc] init] autorelease]; 49 | [task setLaunchPath:@"/usr/bin/gzip"]; 50 | [task setArguments:[NSArray arrayWithObject:filePath]]; 51 | [task launch]; 52 | [task waitUntilExit]; 53 | 54 | NSData *deflatedData = [NSData dataWithContentsOfFile:gzippedFilePath]; 55 | 56 | NSData *inflatedData = [ASIDataDecompressor uncompressData:deflatedData error:&error]; 57 | if (error) { 58 | GHFail(@"Inflate failed because %@",error); 59 | } 60 | 61 | NSString *inflatedString = [[[NSString alloc] initWithBytes:[inflatedData bytes] length:[inflatedData length] encoding:NSUTF8StringEncoding] autorelease]; 62 | 63 | 64 | BOOL success = [inflatedString isEqualToString:originalString]; 65 | GHAssertTrue(success,@"inflated data is not the same as original"); 66 | 67 | // Test file to file inflate 68 | NSString *inflatedFilePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"inflated_file.txt"]; 69 | [ASIHTTPRequest removeFileAtPath:inflatedFilePath error:&error]; 70 | if (error) { 71 | GHFail(@"Failed to remove old file, cannot proceed with test"); 72 | } 73 | 74 | if (![ASIDataDecompressor uncompressDataFromFile:gzippedFilePath toFile:inflatedFilePath error:&error]) { 75 | GHFail(@"Inflate failed because %@",error); 76 | } 77 | 78 | originalString = [NSString stringWithContentsOfFile:inflatedFilePath encoding:NSUTF8StringEncoding error:&error]; 79 | if (error) { 80 | GHFail(@"Failed to read the inflated data, cannot proceed with test"); 81 | } 82 | 83 | success = [inflatedString isEqualToString:originalString]; 84 | GHAssertTrue(success,@"inflated data is not the same as original"); 85 | 86 | } 87 | 88 | - (void)testDeflateData 89 | { 90 | 91 | NSString *originalString = [NSString stringWithContentsOfFile:[[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"story.txt"] encoding:NSUTF8StringEncoding error:NULL]; 92 | 93 | // Test in-memory deflate using compressData:error: 94 | NSError *error = nil; 95 | NSData *deflatedData = [ASIDataCompressor compressData:[originalString dataUsingEncoding:NSUTF8StringEncoding] error:&error]; 96 | if (error) { 97 | GHFail(@"Failed to deflate the data"); 98 | } 99 | 100 | NSString *gzippedFilePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"uncompressed_file.txt.gz"]; 101 | [ASIHTTPRequest removeFileAtPath:gzippedFilePath error:&error]; 102 | if (error) { 103 | GHFail(@"Failed to remove old file, cannot proceed with test"); 104 | } 105 | 106 | [deflatedData writeToFile:gzippedFilePath options:0 error:&error]; 107 | if (error) { 108 | GHFail(@"Failed to write data, cannot proceed with test"); 109 | } 110 | 111 | NSString *filePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"uncompressed_file.txt"]; 112 | [ASIHTTPRequest removeFileAtPath:filePath error:&error]; 113 | if (error) { 114 | GHFail(@"Failed to remove old file, cannot proceed with test"); 115 | } 116 | 117 | NSTask *task = [[[NSTask alloc] init] autorelease]; 118 | [task setLaunchPath:@"/usr/bin/gzip"]; 119 | [task setArguments:[NSArray arrayWithObjects:@"-d",gzippedFilePath,nil]]; 120 | [task launch]; 121 | [task waitUntilExit]; 122 | 123 | NSString *inflatedString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error]; 124 | if (error) { 125 | GHFail(@"Failed to read the inflated data, cannot proceed with test"); 126 | } 127 | 128 | BOOL success = [inflatedString isEqualToString:originalString]; 129 | GHAssertTrue(success,@"inflated data is not the same as original"); 130 | 131 | 132 | // Test file to file deflate 133 | [ASIHTTPRequest removeFileAtPath:gzippedFilePath error:&error]; 134 | 135 | if (![ASIDataCompressor compressDataFromFile:filePath toFile:gzippedFilePath error:&error]) { 136 | GHFail(@"Deflate failed because %@",error); 137 | } 138 | [ASIHTTPRequest removeFileAtPath:filePath error:&error]; 139 | 140 | task = [[[NSTask alloc] init] autorelease]; 141 | [task setLaunchPath:@"/usr/bin/gzip"]; 142 | [task setArguments:[NSArray arrayWithObjects:@"-d",gzippedFilePath,nil]]; 143 | [task launch]; 144 | [task waitUntilExit]; 145 | 146 | inflatedString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error]; 147 | 148 | success = ([inflatedString isEqualToString:originalString]); 149 | GHAssertTrue(success,@"deflate data is not the same as that generated by gzip"); 150 | 151 | // Test for bug https://github.com/pokeb/asi-http-request/issues/147 152 | [ASIHTTPRequest removeFileAtPath:gzippedFilePath error:&error]; 153 | [ASIHTTPRequest removeFileAtPath:filePath error:&error]; 154 | 155 | ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://spaceharvest.com/i/screen6.png"]]; 156 | [request setDownloadDestinationPath:filePath]; 157 | [request startSynchronous]; 158 | 159 | if (![ASIDataCompressor compressDataFromFile:filePath toFile:gzippedFilePath error:&error]) { 160 | GHFail(@"Deflate failed because %@",error); 161 | } 162 | 163 | unsigned long long originalFileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error] fileSize]; 164 | [ASIHTTPRequest removeFileAtPath:filePath error:&error]; 165 | 166 | task = [[[NSTask alloc] init] autorelease]; 167 | [task setLaunchPath:@"/usr/bin/gzip"]; 168 | [task setArguments:[NSArray arrayWithObjects:@"-d",gzippedFilePath,nil]]; 169 | [task launch]; 170 | [task waitUntilExit]; 171 | 172 | unsigned long long inflatedFileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error] fileSize]; 173 | 174 | success = (originalFileSize == inflatedFileSize); 175 | GHAssertTrue(success,@"inflated data is not the same size as the original"); 176 | 177 | } 178 | 179 | @end 180 | --------------------------------------------------------------------------------