Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Kozmicstu

macrumors newbie
Original poster
Nov 22, 2005
5
0
England
Hi

I'm trying to send a multipart/form-data 'POST' request using NSURLRequest, including several keys, but also an image. I'm not particularly knowledgeable on HTTP request (and pretty new to Cocoa, to be honest...)

If you want to know what it's for, right now I'm trying to work against the Tumblr API to post a photo to a Tumblelog from a Cocoa app. I've managed to make text posts from the app, but I can't work out how to do a photo post.

I've been looking on forums and there's a couple of people with really long-winded solutions but I haven't managed to get any of them working. The connection starts and then a message comes back saying 'posts cannot be empty', suggesting that the authentication is fine, but it's not receiving the data part of the message

Anyway, I'd be grateful for any help, if anyone knows how to make this happen :)

Stu
 
Thanks very much for that. I had found one of them before and tried it, but I gave it another go and got it working perfectly. I think I might have been leaving keys out somewhere along the way or something...

Anyway, here's the (probably messy) code I used in the end, for posterity's sake (or for anyone else who wants to do this...)

Code:
- (BOOL)sendPhotoToTumblr:(NSString *)photo withCaption:(NSString *)caption;
{
	//get image data from file
	NSData *imageData = [NSData dataWithContentsOfFile:photo];	
	//stop on error
	if (!imageData) return NO;
	
	//Create dictionary of post arguments
	NSArray *keys = [[NSArray alloc] initWithObjects:@"email",@"password",@"type",@"caption",nil];
	NSArray *objects = [[NSArray alloc] initWithObjects:
			[NSString stringWithFormat:@"%@",CFPreferencesCopyAppValue(CFSTR("TumblrEmail"), kCFPreferencesCurrentApplication)],
			[NSString stringWithFormat:@"%@",CFPreferencesCopyAppValue(CFSTR("TumblrPassword"), kCFPreferencesCurrentApplication)],
			@"photo", caption, nil];
	NSDictionary *keysDict = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
	
	//create tumblr photo post
	NSURLRequest *tumblrPost = [self createTumblrRequest:keysDict withData:imageData];
	
	//send request, return YES if successful
	tumblrConnection = [[NSURLConnection alloc] initWithRequest:tumblrPost delegate:self];
	if (!tumblrConnection) {
		NSLog(@"Failed to submit request");
		return NO;
	} else {
		NSLog(@"Request submitted");
		receivedData = [[NSMutableData data] retain];
		return YES;
	}
}


-(NSURLRequest *)createTumblrRequest:(NSDictionary *)postKeys withData:(NSData *)data
{
	//create the URL POST Request to tumblr
	NSURL *tumblrURL = [NSURL URLWithString:@"http://www.tumblr.com/api/write"];
	NSMutableURLRequest *tumblrPost = [NSMutableURLRequest requestWithURL:tumblrURL];
	[tumblrPost setHTTPMethod:@"POST"];
	
	//Add the header info
	NSString *stringBoundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"];
	NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary];
	[tumblrPost addValue:contentType forHTTPHeaderField: @"Content-Type"];
	
	//create the body
	NSMutableData *postBody = [NSMutableData data];
	[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
	
	//add key values from the NSDictionary object
	NSEnumerator *keys = [postKeys keyEnumerator];
	int i;
	for (i = 0; i < [postKeys count]; i++) {
		NSString *tempKey = [keys nextObject];
		[postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",tempKey] dataUsingEncoding:NSUTF8StringEncoding]];
		[postBody appendData:[[NSString stringWithFormat:@"%@",[postKeys objectForKey:tempKey]] dataUsingEncoding:NSUTF8StringEncoding]];
		[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
	}

	//add data field and file data
	[postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"data\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[NSData dataWithData:data]];
	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
	
	//add the body to the post
	[tumblrPost setHTTPBody:postBody];

	return tumblrPost;
}
 
Make sure you release or autorelease your keys, objects, and keysDict variables. You're leaking memory if you don't (unless you have GC on).
 
This post has helped me out a ton!

The one thing I can't figure out is how to make a module appear for users to enter their email / pass to log into tumblr to share the image.

any tips on this?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.