Permalink
Browse files

Refactor: move multipart form stuff into subclass

Added iphone example
  • Loading branch information...
1 parent 0fbb974 commit d9cbde9cd37fc9e57e08d1ca3d593124d62bde57 @pokeb committed Nov 7, 2008
View
@@ -0,0 +1,29 @@
+//
+// ASIFormDataRequest.h
+// asi-http-request
+//
+// Created by Ben Copsey on 07/11/2008.
+// Copyright 2008 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIHTTPRequest.h"
+
+@interface ASIFormDataRequest : ASIHTTPRequest {
+
+ //Parameters that will be POSTed to the url
+ NSMutableDictionary *postData;
+
+ //Files that will be POSTed to the url
+ NSMutableDictionary *fileData;
+
+}
+
+#pragma mark setup request
+
+//Add a POST variable to the request
+- (void)setPostValue:(id)value forKey:(NSString *)key;
+
+//Add the contents of a local file as a POST variable to the request
+- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
+
+@end
View
@@ -0,0 +1,113 @@
+//
+// ASIFormDataRequest.m
+// asi-http-request
+//
+// Created by Ben Copsey on 07/11/2008.
+// Copyright 2008 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIFormDataRequest.h"
+
+
+@implementation ASIFormDataRequest
+
+#pragma mark init / dealloc
+
+- (id)initWithURL:(NSURL *)newURL
+{
+ self = [super initWithURL:newURL];
+ postData = nil;
+ fileData = nil;
+ return self;
+}
+
+- (void)dealloc
+{
+ [postData release];
+ [fileData release];
+ [super dealloc];
+}
+
+#pragma mark setup request
+
+- (void)setPostValue:(id)value forKey:(NSString *)key
+{
+ if (!postData) {
+ postData = [[NSMutableDictionary alloc] init];
+ }
+ [postData setValue:value forKey:key];
+}
+
+- (void)setFile:(NSString *)filePath forKey:(NSString *)key
+{
+ if (!fileData) {
+ fileData = [[NSMutableDictionary alloc] init];
+ }
+ [fileData setValue:filePath forKey:key];
+}
+
+
+#pragma mark request logic
+
+// Create the request
+- (void)main
+{
+
+ // If the user didn't specify post data, we will let ASIHTTPRequest use the value of postBody
+ if ([postData count] == 0 && [fileData count] == 0) {
+ [super main];
+ return;
+ }
+
+ //Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
+ NSString *stringBoundary = @"0xKhTmLbOuNdArY";
+
+ if ([fileData count] > 0) {
+ //We need to use multipart/form-data when using file upload
+ [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]];
+ }
+
+ //Since we've got post data, let's set the post body to an empty NSMutableData object
+ [self setPostBody:[NSMutableData data]];
+
+ [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
+
+ //Adds post data
+ NSData *endItemBoundary = [[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding];
+ NSEnumerator *e = [postData keyEnumerator];
+ NSString *key;
+ int i=0;
+ while (key = [e nextObject]) {
+ [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key] dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[[postData objectForKey:key] dataUsingEncoding:NSUTF8StringEncoding]];
+ i++;
+ if (i != [postData count] || [fileData count] > 0) { //Only add the boundary if this is not the last item in the post body
+ [postBody appendData:endItemBoundary];
+ }
+ }
+
+ //Adds files to upload
+ NSData *contentTypeHeader = [[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding];
+ e = [fileData keyEnumerator];
+ i=0;
+ while (key = [e nextObject]) {
+ NSString *filePath = [fileData objectForKey:key];
+ [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",key,[filePath lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:contentTypeHeader];
+ [postBody appendData:[NSData dataWithContentsOfMappedFile:filePath]];
+ i++;
+ if (i != [fileData count]) { //Only add the boundary if this is not the last item in the post body
+ [postBody appendData:endItemBoundary];
+ }
+ }
+
+ [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
+
+ //Now we've created our post data, construct the request
+ [super main];
+
+}
+
+
+
+@end
View
@@ -10,11 +10,9 @@
// Portions are based on the ImageClient example from Apple:
// See: http://developer.apple.com/samplecode/ImageClient/listing37.html
-#import <Cocoa/Cocoa.h>
#import "ASIProgressDelegate.h"
-
@interface ASIHTTPRequest : NSOperation {
//The url for this operation, should include GET params in the query string where appropriate
@@ -23,11 +21,11 @@
//The delegate, you need to manage setting and talking to your delegate in your subclasses
id delegate;
- //Parameters that will be POSTed to the url
- NSMutableDictionary *postData;
+ //HTTP method to use (GET / POST / PUT / DELETE). Defaults to GET
+ NSString *requestMethod;
- //Files that will be POSTed to the url
- NSMutableDictionary *fileData;
+ //Request body
+ NSMutableData *postBody;
//Dictionary for custom HTTP request headers
NSMutableDictionary *requestHeaders;
@@ -138,11 +136,6 @@
//Add a custom header to the request
- (void)addRequestHeader:(NSString *)header value:(NSString *)value;
-//Add a POST variable to the request
-- (void)setPostValue:(id)value forKey:(NSString *)key;
-
-//Add the contents of a local file as a POST variable to the request
-- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
#pragma mark get information about this request
@@ -259,4 +252,6 @@
@property (retain) NSMutableData *receivedData;
@property (retain) NSDate *lastActivityTime;
@property (assign) NSTimeInterval timeOutSeconds;
+@property (retain) NSString *requestMethod;
+@property (retain) NSMutableData *postBody;
@end
View
@@ -38,10 +38,9 @@ @implementation ASIHTTPRequest
- (id)initWithURL:(NSURL *)newURL
{
- [super init];
+ self = [super init];
+ [self setRequestMethod:@"GET"];
lastBytesSent = 0;
- postData = nil;
- fileData = nil;
username = nil;
password = nil;
requestHeaders = nil;
@@ -72,19 +71,24 @@ - (void)dealloc
CFRelease(request);
}
[self cancelLoad];
+ [postBody release];
[requestCredentials release];
[error release];
- [postData release];
- [fileData release];
[requestHeaders release];
+ [requestCookies release];
[downloadDestinationPath release];
[outputStream release];
[username release];
[password release];
+ [domain release];
[authenticationRealm release];
[url release];
[authenticationLock release];
[lastActivityTime release];
+ [responseCookies release];
+ [receivedData release];
+ [responseHeaders release];
+ [requestMethod release];
[super dealloc];
}
@@ -100,23 +104,6 @@ - (void)addRequestHeader:(NSString *)header value:(NSString *)value
}
-- (void)setPostValue:(id)value forKey:(NSString *)key
-{
- if (!postData) {
- postData = [[NSMutableDictionary alloc] init];
- }
- [postData setValue:value forKey:key];
-}
-
-- (void)setFile:(NSString *)filePath forKey:(NSString *)key
-{
- if (!fileData) {
- fileData = [[NSMutableDictionary alloc] init];
- }
- [fileData setValue:filePath forKey:key];
-}
-
-
#pragma mark get information about this request
- (BOOL)isFinished
@@ -145,15 +132,9 @@ - (NSString *)dataString
- (void)main
{
complete = NO;
-
- // We'll make a post request only if the user specified post data
- NSString *method = @"GET";
- if ([postData count] > 0 || [fileData count] > 0) {
- method = @"POST";
- }
// Create a new HTTP request.
- request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)method, (CFURLRef)url, kCFHTTPVersion1_1);
+ request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)requestMethod, (CFURLRef)url, kCFHTTPVersion1_1);
if (!request) {
[self failWithProblem:[NSString stringWithFormat:@"Unable to create request for: %@",url]];
return;
@@ -166,9 +147,6 @@ - (void)main
[ASIHTTPRequest setSessionCredentials:nil];
}
}
-
- //Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
- NSString *stringBoundary = @"0xKhTmLbOuNdArY";
//Add cookies from the persistant (mac os global) store
if (useCookiePersistance) {
@@ -200,48 +178,11 @@ - (void)main
for (header in requestHeaders) {
CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[requestHeaders objectForKey:header]);
}
- CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)@"Content-Type", (CFStringRef)[NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]);
-
- if ([postData count] > 0 || [fileData count] > 0) {
-
- NSMutableData *postBody = [NSMutableData data];
- [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
-
- //Adds post data
- NSData *endItemBoundary = [[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding];
- NSEnumerator *e = [postData keyEnumerator];
- NSString *key;
- int i=0;
- while (key = [e nextObject]) {
- [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key] dataUsingEncoding:NSUTF8StringEncoding]];
- [postBody appendData:[[postData objectForKey:key] dataUsingEncoding:NSUTF8StringEncoding]];
- i++;
- if (i != [postData count] || [fileData count] > 0) { //Only add the boundary if this is not the last item in the post body
- [postBody appendData:endItemBoundary];
- }
- }
-
- //Adds files to upload
- NSData *contentTypeHeader = [[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding];
- e = [fileData keyEnumerator];
- i=0;
- while (key = [e nextObject]) {
- NSString *filePath = [fileData objectForKey:key];
- [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",key,[filePath lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
- [postBody appendData:contentTypeHeader];
- [postBody appendData:[NSData dataWithContentsOfMappedFile:filePath]];
- i++;
- if (i != [fileData count]) { //Only add the boundary if this is not the last item in the post body
- [postBody appendData:endItemBoundary];
- }
- }
-
- [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Set the body.
+
+ //If this is a post request and we have data to send, add it to the request
+ if ([self postBody]) {
CFHTTPMessageSetBody(request, (CFDataRef)postBody);
-
postLength = [postBody length];
}
@@ -887,4 +828,6 @@ + (void)clearSession
@synthesize receivedData;
@synthesize lastActivityTime;
@synthesize timeOutSeconds;
+@synthesize requestMethod;
+@synthesize postBody;
@end
View
@@ -5,7 +5,6 @@
// Copyright 2008 All-Seeing Interactive. All rights reserved
//
-#import <Cocoa/Cocoa.h>
@protocol ASIProgressDelegate
View
@@ -5,7 +5,6 @@
// Copyright 2008 All-Seeing Interactive Ltd. All rights reserved.
//
-#import <Cocoa/Cocoa.h>
@class ASIHTTPRequest;
@interface AppDelegate : NSObject {
View
@@ -7,6 +7,7 @@
#import "AppDelegate.h"
#import "ASIHTTPRequest.h"
+#import "ASIFormDataRequest.h"
@implementation AppDelegate
@@ -26,7 +27,7 @@ - (void)dealloc
- (IBAction)simpleURLFetch:(id)sender
{
- ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://asi/"]] autorelease];
+ ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/"]] autorelease];
//Customise our user agent, for no real reason
[request addRequestHeader:@"User-Agent" value:@"ASIHTTPRequest"];
@@ -165,7 +166,7 @@ - (IBAction)postWithProgress:(id)sender
[networkQueue cancelAllOperations];
[progressIndicator setDoubleValue:0];
- ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease];
+ ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease];
[request setDelegate:self];
[request setUploadProgressDelegate:progressIndicator];
[request setPostValue:@"test" forKey:@"value1"];
View
@@ -0,0 +1,16 @@
+//
+// FirstViewController.h
+// tabtest
+//
+// Created by Ben Copsey on 07/11/2008.
+// Copyright All-Seeing Interactive 2008. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface FirstViewController : UIViewController {
+
+}
+
+@end
Oops, something went wrong.

0 comments on commit d9cbde9

Please sign in to comment.