Ben Copsey

First public release

  1 +//
  2 +// ASIHTTPRequest.h
  3 +//
  4 +// Created by Ben Copsey on 04/10/2007.
  5 +// Copyright 2007-2008 All-Seeing Interactive. All rights reserved.
  6 +//
  7 +// Portions are based on the ImageClient example from Apple:
  8 +// See: http://developer.apple.com/samplecode/ImageClient/listing37.html
  9 +
  10 +#import <Cocoa/Cocoa.h>
  11 +#import "ASIProgressDelegate.h"
  12 +
  13 +@interface ASIHTTPRequest : NSOperation {
  14 +
  15 + //The url for this operation, should include get params in the query string where appropriate
  16 + NSURL *url;
  17 +
  18 + //The delegate, you need to manage setting and talking to your delegate in your subclasses
  19 + id delegate;
  20 +
  21 + //Parameters that will be POSTed to the url
  22 + NSMutableDictionary *postData;
  23 +
  24 + //Files that will be POSTed to the url
  25 + NSMutableDictionary *fileData;
  26 +
  27 + //Dictionary for custom request headers
  28 + NSMutableDictionary *requestHeaders;
  29 +
  30 + //If usesKeychain is true, network requests will attempt to read credentials from the keychain, and will save them in the keychain when they are successfully presented
  31 + BOOL usesKeychain;
  32 +
  33 + //When downloadDestinationPath is set, the result of this request will be downloaded to the file at this location
  34 + //If downloadDestinationPath is not set, download data will be stored in memory
  35 + NSString *downloadDestinationPath;
  36 +
  37 + //Used for writing data to a file when downloadDestinationPath is set
  38 + NSOutputStream *outputStream;
  39 +
  40 + //When the request fails or completes successfully, complete will be true
  41 + BOOL complete;
  42 +
  43 + //If an error occurs, error will contain an NSError
  44 + NSError *error;
  45 +
  46 + //If an authentication error occurs, we give the delegate a chance to handle it, ignoreError will be set to true
  47 + BOOL ignoreError;
  48 +
  49 + //Username and password used for authentication
  50 + NSString *username;
  51 + NSString *password;
  52 +
  53 + //Delegate for displaying upload progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
  54 + NSObject <ASIProgressDelegate> *uploadProgressDelegate;
  55 +
  56 + //Delegate for displaying download progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
  57 + NSObject <ASIProgressDelegate> *downloadProgressDelegate;
  58 +
  59 + // Whether we've seen the headers of the response yet
  60 + BOOL haveExaminedHeaders;
  61 +
  62 + //Data we receive will be stored here
  63 + CFMutableDataRef receivedData;
  64 +
  65 + //Used for sending and receiving data
  66 + CFHTTPMessageRef request;
  67 + CFReadStreamRef readStream;
  68 +
  69 + // Authentication currently being used for prompting and resuming
  70 + CFHTTPAuthenticationRef authentication;
  71 +
  72 + // Credentials associated with the authentication (reused until server says no)
  73 + CFMutableDictionaryRef credentials;
  74 +
  75 + //Size of the response
  76 + double contentLength;
  77 +
  78 + //Size of the POST payload
  79 + double postLength;
  80 +
  81 + //Timer used to update the progress delegates
  82 + NSTimer *progressTimer;
  83 +
  84 + //The total amount of downloaded data
  85 + double totalBytesRead;
  86 +
  87 + //Realm for authentication when credentials are required
  88 + NSString *authenticationRealm;
  89 +
  90 + //Called on the delegate when the request completes successfully
  91 + SEL didFinishSelector;
  92 +
  93 + //Called on the delegate when the request fails
  94 + SEL didFailSelector;
  95 +
  96 + //This lock will block the request until the delegate supplies authentication info
  97 + NSConditionLock *authenticationLock;
  98 +}
  99 +
  100 +// Should be an HTTP or HTTPS url, may include username and password if appropriate
  101 +- (id)initWithURL:(NSURL *)newURL;
  102 +
  103 +//Add a POST variable to the request
  104 +- (void)setPostValue:(id)value forKey:(NSString *)key;
  105 +
  106 +//Add the contents of a local file as a POST variable to the request
  107 +- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
  108 +
  109 +//Add a custom header to the request
  110 +- (void)addRequestHeader:(NSString *)header value:(NSString *)value;
  111 +
  112 +//the results of this request will be saved to downloadDestinationPath, if it is set
  113 +- (void)setDownloadDestinationPath:(NSString *)newDestinationPath;
  114 +- (NSString *)downloadDestinationPath;
  115 +
  116 +// When set, username and password will be presented for HTTP authentication
  117 +- (void)setUsername:(NSString *)newUsername andPassword:(NSString *)newPassword;
  118 +
  119 +// Delegate will get messages when the request completes, fails or when authentication is required
  120 +- (void)setDelegate:(id)newDelegate;
  121 +
  122 +// Called on the delegate when the request completes successfully
  123 +- (void)setDidFinishSelector:(SEL)selector;
  124 +
  125 +// Called on the delegate when the request fails
  126 +- (void)setDidFailSelector:(SEL)selector;
  127 +
  128 +// upload progress delegate (usually an NSProgressIndicator) is sent information on upload progress
  129 +- (void)setUploadProgressDelegate:(id)newDelegate;
  130 +
  131 +// download progress delegate (usually an NSProgressIndicator) is sent information on download progress
  132 +- (void)setDownloadProgressDelegate:(id)newDelegate;
  133 +
  134 +// When true, authentication information will automatically be stored in (and re-used from) the keychain
  135 +- (void)setUsesKeychain:(BOOL)shouldUseKeychain;
  136 +
  137 +// Will be true when the request is complete (success or failure)
  138 +- (BOOL)complete;
  139 +
  140 +// Returns the contents of the result as an NSString (not appropriate for binary data!)
  141 +- (NSString *)dataString;
  142 +
  143 +// Accessors for getting information about the request (useful for auth dialogs)
  144 +- (NSString *)authenticationRealm;
  145 +- (NSString *)host;
  146 +
  147 +// Contains a description of the error that occurred if the request failed
  148 +- (NSError *)error;
  149 +
  150 +
  151 +// CFnetwork event handlers
  152 +- (void)handleStreamComplete;
  153 +- (void)handleStreamError;
  154 +- (void)handleBytesAvailable;
  155 +- (void)handleNetworkEvent:(CFStreamEventType)type;
  156 +
  157 +// Start loading the request
  158 +- (void)loadRequest;
  159 +
  160 +// Reads the response headers to find the content length, and returns true if the request needs a username and password (or if those supplied were incorrect)
  161 +- (BOOL)isAuthorizationFailure;
  162 +
  163 +// Apply authentication information and resume the request after an authentication challenge
  164 +- (void)applyCredentialsAndResume;
  165 +
  166 +// Unlock (unpause) the request thread so it can resume the request
  167 +// Should be called by delegates when they have populated the authentication information after an authentication challenge
  168 +- (void)retryWithAuthentication;
  169 +
  170 +// Cancel loading and clean up
  171 +- (void)cancelLoad;
  172 +
  173 +// Called from timer on main thread to update progress delegates
  174 +- (void)updateUploadProgress;
  175 +- (void)updateDownloadProgress;
  176 +
  177 +#pragma mark keychain stuff
  178 +
  179 +//Save credentials to the keychain
  180 ++ (void)saveCredentials:(NSURLCredential *)credentials forHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
  181 +
  182 +//Return credentials from the keychain
  183 ++ (NSURLCredential *)savedCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
  184 +
  185 +//Called when a request completes successfully
  186 +- (void)requestFinished;
  187 +
  188 +//Called when a request fails
  189 +- (void)failWithProblem:(NSString *)problem;
  190 +
  191 +@end
This diff is collapsed. Click to expand it.
  1 +//
  2 +// ASIProgressDelegate.h
  3 +//
  4 +// Created by Ben Copsey on 28/03/2008.
  5 +// Copyright 2008 All-Seeing Interactive. All rights reserved
  6 +//
  7 +
  8 +#import <Cocoa/Cocoa.h>
  9 +
  10 +@protocol ASIProgressDelegate
  11 +
  12 +- (void)incrementProgress;
  13 +- (void)setDoubleValue:(double)newValue;
  14 +- (void)incrementBy:(double)amount;
  15 +- (void)setMaxValue:(double)newMax;
  16 +@end
  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 <Cocoa/Cocoa.h>
  9 +@class ASIHTTPRequest;
  10 +
  11 +@interface AppDelegate : NSObject {
  12 + NSOperationQueue *networkQueue;
  13 + IBOutlet NSProgressIndicator *progressIndicator;
  14 + IBOutlet NSTextView *htmlSource;
  15 + IBOutlet NSTextField *fileLocation;
  16 + IBOutlet NSWindow *window;
  17 + IBOutlet NSWindow *loginWindow;
  18 +
  19 + IBOutlet NSTextField *host;
  20 + IBOutlet NSTextField *realm;
  21 + IBOutlet NSTextField *username;
  22 + IBOutlet NSTextField *password;
  23 +
  24 + IBOutlet NSTextField *topSecretInfo;
  25 + IBOutlet NSButton *keychainCheckbox;
  26 +
  27 + IBOutlet NSImageView *imageView1;
  28 + IBOutlet NSImageView *imageView2;
  29 + IBOutlet NSImageView *imageView3;
  30 +}
  31 +
  32 +- (IBAction)simpleURLFetch:(id)sender;
  33 +- (IBAction)URLFetchWithProgress:(id)sender;
  34 +
  35 +
  36 +- (IBAction)fetchThreeImages:(id)sender;
  37 +
  38 +- (void)authorizationNeededForRequest:(ASIHTTPRequest *)request;
  39 +- (IBAction)dismissAuthSheet:(id)sender;
  40 +- (IBAction)fetchTopSecretInformation:(id)sender;
  41 +
  42 +- (IBAction)postWithProgress:(id)sender;
  43 +@end
  1 +//
  2 +// AppDelegate.m
  3 +//
  4 +// Created by Ben Copsey on 09/07/2008.
  5 +// Copyright 2008 All-Seeing Interactive Ltd. All rights reserved.
  6 +//
  7 +
  8 +#import "AppDelegate.h"
  9 +#import "ASIHTTPRequest.h"
  10 +
  11 +@implementation AppDelegate
  12 +
  13 +- (id)init
  14 +{
  15 + [super init];
  16 + networkQueue = [[NSOperationQueue alloc] init];
  17 + return self;
  18 +}
  19 +
  20 +- (void)dealloc
  21 +{
  22 + [networkQueue release];
  23 + [super dealloc];
  24 +}
  25 +
  26 +
  27 +- (IBAction)simpleURLFetch:(id)sender
  28 +{
  29 + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]] autorelease];
  30 + [request start];
  31 + if ([request dataString]) {
  32 + [htmlSource setString:[request dataString]];
  33 + }
  34 +}
  35 +
  36 +
  37 +- (IBAction)URLFetchWithProgress:(id)sender
  38 +{
  39 + [networkQueue cancelAllOperations];
  40 + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://trails-network.net/Downloads/MemexTrails_1.0b1.zip"]] autorelease];
  41 + [request setDelegate:self];
  42 + [request setDownloadProgressDelegate:progressIndicator];
  43 + [request setDidFinishSelector:@selector(URLFetchWithProgressComplete:)];
  44 + [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"MemexTrails_1.0b1.zip"]];
  45 + [networkQueue addOperation:request];
  46 +}
  47 +
  48 +- (void)URLFetchWithProgressComplete:(ASIHTTPRequest *)request
  49 +{
  50 + if ([request error]) {
  51 + [fileLocation setStringValue:[NSString stringWithFormat:@"An error occurred: %@",[[[request error] userInfo] objectForKey:@"Title"]]];
  52 + } else {
  53 + [fileLocation setStringValue:[NSString stringWithFormat:@"File downloaded to %@",[request downloadDestinationPath]]];
  54 + }
  55 +}
  56 +
  57 +- (IBAction)fetchThreeImages:(id)sender
  58 +{
  59 + [imageView1 setImage:nil];
  60 + [imageView2 setImage:nil];
  61 + [imageView3 setImage:nil];
  62 +
  63 + [networkQueue cancelAllOperations];
  64 + [progressIndicator setDoubleValue:0];
  65 + [progressIndicator setMaxValue:3];
  66 + ASIHTTPRequest *request;
  67 + request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/logo.png"]] autorelease];
  68 + [request setDelegate:self];
  69 + [request setDidFinishSelector:@selector(imageFetchComplete:)];
  70 + [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"1.png"]];
  71 + [networkQueue addOperation:request];
  72 +
  73 + request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/trailsnetwork.png"]] autorelease];
  74 + [request setDelegate:self];
  75 + [request setDidFinishSelector:@selector(imageFetchComplete:)];
  76 + [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"2.png"]];
  77 + [networkQueue addOperation:request];
  78 +
  79 + request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/sharedspace20.png"]] autorelease];
  80 + [request setDelegate:self];
  81 + [request setDidFinishSelector:@selector(imageFetchComplete:)];
  82 + [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"3.png"]];
  83 + [networkQueue addOperation:request];
  84 +}
  85 +
  86 +
  87 +- (void)imageFetchComplete:(ASIHTTPRequest *)request
  88 +{
  89 + NSImage *img = [[[NSImage alloc] initWithContentsOfFile:[request downloadDestinationPath]] autorelease];
  90 + if (img) {
  91 + if ([imageView1 image]) {
  92 + if ([imageView2 image]) {
  93 + [imageView3 setImage:img];
  94 + } else {
  95 + [imageView2 setImage:img];
  96 + }
  97 + } else {
  98 + [imageView1 setImage:img];
  99 + }
  100 + }
  101 + [progressIndicator incrementBy:1];
  102 +
  103 +}
  104 +
  105 +
  106 +- (IBAction)fetchTopSecretInformation:(id)sender
  107 +{
  108 + [networkQueue cancelAllOperations];
  109 + [progressIndicator setDoubleValue:0];
  110 + ASIHTTPRequest *request;
  111 + request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/top_secret/"]] autorelease];
  112 + [request setDelegate:self];
  113 + [request setDidFinishSelector:@selector(topSecretFetchComplete:)];
  114 + [request setUsesKeychain:[keychainCheckbox state]];
  115 + [networkQueue addOperation:request];
  116 +
  117 +}
  118 +
  119 +- (IBAction)topSecretFetchComplete:(ASIHTTPRequest *)request
  120 +{
  121 + if (![request error]) {
  122 + [topSecretInfo setStringValue:[request dataString]];
  123 + [topSecretInfo setFont:[NSFont boldSystemFontOfSize:13]];
  124 + }
  125 +}
  126 +
  127 +- (void)authorizationNeededForRequest:(ASIHTTPRequest *)request
  128 +{
  129 + [realm setStringValue:[request authenticationRealm]];
  130 + [host setStringValue:[request host]];
  131 +
  132 + [NSApp beginSheet: loginWindow
  133 + modalForWindow: window
  134 + modalDelegate: self
  135 + didEndSelector: @selector(authSheetDidEnd:returnCode:contextInfo:)
  136 + contextInfo: request];
  137 +}
  138 +
  139 +- (IBAction)dismissAuthSheet:(id)sender {
  140 + [[NSApplication sharedApplication] endSheet: loginWindow returnCode: [(NSControl*)sender tag]];
  141 +}
  142 +
  143 +- (void)authSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
  144 + ASIHTTPRequest *request = (ASIHTTPRequest *)contextInfo;
  145 + if (returnCode == NSOKButton) {
  146 + [request setUsername:[[[username stringValue] copy] autorelease] andPassword:[[[password stringValue] copy] autorelease]];
  147 + [request retryWithAuthentication];
  148 + } else {
  149 + [request cancelLoad];
  150 + }
  151 + [loginWindow orderOut: self];
  152 +}
  153 +
  154 +- (IBAction)postWithProgress:(id)sender
  155 +{
  156 + //Create a 1mb file
  157 + NSMutableData *data = [NSMutableData dataWithLength:1024*1024];
  158 + NSString *path = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"bigfile"];
  159 + [data writeToFile:path atomically:NO];
  160 +
  161 + [networkQueue cancelAllOperations];
  162 + [progressIndicator setDoubleValue:0];
  163 + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease];
  164 + [request setDelegate:self];
  165 + [request setUploadProgressDelegate:progressIndicator];
  166 + [request setPostValue:@"test" forKey:@"value1"];
  167 + [request setPostValue:@"test" forKey:@"value2"];
  168 + [request setPostValue:@"test" forKey:@"value3"];
  169 +
  170 + [request setFile:path forKey:@"file"];
  171 +
  172 + [networkQueue addOperation:request];
  173 +
  174 +}
  175 +
  176 +
  177 +
  178 +@end
1 B/* Localized versions of Info.plist keys */ 1 B/* Localized versions of Info.plist keys */
This diff could not be displayed because it is too large.
No preview for this file type
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>English</string>
  7 + <key>CFBundleExecutable</key>
  8 + <string>${EXECUTABLE_NAME}</string>
  9 + <key>CFBundleIconFile</key>
  10 + <string></string>
  11 + <key>CFBundleIdentifier</key>
  12 + <string>com.allseeing-i.asi-http-request</string>
  13 + <key>CFBundleInfoDictionaryVersion</key>
  14 + <string>6.0</string>
  15 + <key>CFBundleName</key>
  16 + <string>${PRODUCT_NAME}</string>
  17 + <key>CFBundlePackageType</key>
  18 + <string>APPL</string>
  19 + <key>CFBundleSignature</key>
  20 + <string>????</string>
  21 + <key>CFBundleVersion</key>
  22 + <string>1.0</string>
  23 + <key>NSMainNibFile</key>
  24 + <string>MainMenu</string>
  25 + <key>NSPrincipalClass</key>
  26 + <string>NSApplication</string>
  27 +</dict>
  28 +</plist>
  1 +* Copyright (c) 2007-2008, 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 <copyright holder> 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.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff was suppressed by a .gitattributes entry.
  1 +//
  2 +// Prefix header for all source files of the 'asi-http-request' target in the 'asi-http-request' project
  3 +//
  4 +
  5 +#ifdef __OBJC__
  6 + #import <Cocoa/Cocoa.h>
  7 +#endif
  1 +//
  2 +// main.m
  3 +// asi-http-request
  4 +//
  5 +// Created by Ben Copsey on 09/07/2008.
  6 +// Copyright __MyCompanyName__ 2008. All rights reserved.
  7 +//
  8 +
  9 +#import <Cocoa/Cocoa.h>
  10 +
  11 +int main(int argc, char *argv[])
  12 +{
  13 + return NSApplicationMain(argc, (const char **) argv);
  14 +}