2

Im trying to upload an image from the client application to my django webserver. Im trying to create the equivalent of the following curl command using NSURLConnection.

curl -v  -S  -X POST  -H 'Accept: application/json' -F image=@"//Users/mackaiver/someImageOfACat.jpg;type=image/jpg"  -F kiosk="81" http://myurl.de/rest/image/ 

The expected response is the HTTP Status 201 Created and the server does expect some sort of JSON response I presume. When I use a curl line like this

curl -v  -S  -X POST  -H 'Accept: application/json' -F image=@"//Users/mackaiver/someImageOfACat.jpg;type=image/jpg" http://myurl.de/rest/image/

I expect a 400 Bad Request respone. So far so good. This works fine via curl on the command line. Now I want to do this in iOS. So far Im thinking I can use following code to send an image.

NSString *urlString = [ NSString stringWithFormat:@"%@image",REST_BASE_URL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];

NSData *imageData = UIImageJPEGRepresentation(image, 1.0);


NSString *boundary = @"----------------------------6f875f2289c9";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

NSMutableData *body = [NSMutableData data];

// file
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Disposition: attachment; name=\"image\"; filename=\"image_upload.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
[body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

Now for some reason this creates a 200 OK response which is not at all what I expected. Also I dont know how to add the kiosk=81 parameter. Is there any way to do this? Should I use an external library like AFNetworking?

Thanks in advance :)

EDIT:

This is what my code looks like now. Looking at the wireshark output from both the curl command and my app I cant seem to find any differences.

NSString *urlString = [ NSString stringWithFormat:@"%@image",BASE_URL];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];


NSString *boundary = @"--6ee875e2289c9";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
NSString *accept = @"application/json";

[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
[request setValue:accept forHTTPHeaderField: @"Accept"];
[request setHTTPMethod:@"POST"];


NSMutableData *body = [NSMutableData data];

[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\"; filename=\"bla.jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];

[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"kiosk\"\r\n\r\n%@", kioskId] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

[request setHTTPBody:body];
self.connection = [[NSURLConnection alloc]
                   initWithRequest:request
                   delegate:self];
macKaiver
  • 691
  • 8
  • 13

1 Answers1

3

Your Django web service expects a multipart/form-data request with:

  • a Accept: application/json custom header field,
  • image and kiosk parameters.

You know how to achieve this with curl, from the command line, thanks to the following options:

  1. -H/--header <line> to set your custom header,
  2. -X POST to issue a POST request,
  3. -F/--form <name=content> to specify multipart POST data.

In Objective-C with NSURLConnection and NSURLRequest you need to do the equivalent of the above options:

  1. you can set a custom header on your NSURLRequest instance thanks to the addValue:forHTTPHeaderField: method,
  2. you can perform a POST request via [request setHTTPMethod:@"POST"];,
  3. you need to set a properly formatted body string with [request setHTTPBody:body];.

So the question is: how do I manually create a multipart/form-data body string with my image and kiosk parameters?

The RFC and curl --trace-ascii out.txt ... may help you building the body (note that you need 2 boundary sections since you have 2 parameters).

Alternatively you can easily find many samples on how to do that, e.g: Sending Multipart Forms with Objective-C.

At last, AFNetworking is a convenient wrapper around NSURLConnection. It is particularly handy since it provides a ready-to-use multipartFormRequestWithMethod method used to perform multipart POST requests. So you can use it as an alternative.

Community
  • 1
  • 1
deltheil
  • 15,496
  • 2
  • 44
  • 64
  • Thank you! Im afraid I cant seem to get this to work. I compared the wireshark output from the curl command with the output from my app. I cant make out any differences. I updated my post to contain my most recent ios code. Maybe ill just try the AFNetworling bit. – macKaiver Sep 15 '13 at 11:42
  • I used the AFNetworking lib as described in this [link](http://stackoverflow.com/questions/16692102/send-image-along-with-other-parameters-with-afnetworking) SO question. Again the wireshark output looks similar to the curl post. Still I get a 200 OK response whatever data I send. I'd expect some 400 errors at least. – macKaiver Sep 15 '13 at 12:17
  • I got it to work with AFNetworking now :D Guess im gonna switch the whole application to use that library. Thanks again. – macKaiver Sep 15 '13 at 12:23
  • And what about the wireshark output w/ AFNetworking? You should refer to [AFStreamingMultipartFormData](https://github.com/AFNetworking/AFNetworking/blob/44915d517302a7c7a87fb6c8bf2bd22281e57964/AFNetworking/AFHTTPClient.m#L828) implementation and compare it with your code to understand what's wrong! – deltheil Sep 15 '13 at 16:50