4

I know this may seem specific to the issue at hand, however, this is me trying to avoid the horrible UploadCare usage of cocoa pods which contains a significant (and rather outdated) amount of dependencies, to JUST upload a file (and subsequently download it at a later date).

I'm struggling to translate the '-F' options in the cURL command. I understand that they specify HTTP multipart POST data, but converting this into NSMutableData with the picture file attached is difficult. I keep receiving a 403 status code.

The cURL command is:

curl -F "UPLOADCARE_PUB_KEY=e84a031b3da1g560d56d"  \
-F "UPLOADCARE_STORE=1"  \
-F "file=@aaronmillman.jpg" https://upload.uploadcare.com/base/

My current attempt is:

NSMutableData *body = [NSMutableData data];
NSData *imageData = UIImageJPEGRepresentation(image, 0.6);
if (imageData) {
    [body appendData:[@"UPLOADCARE_PUB_KEY=e84a031b3da1g560d56d" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"UPLOADCARE_STORE=1" dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"file="] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:imageData];
}

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];

NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];

NSURL *url = [NSURL URLWithString:baseUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = imageData;
NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSLog(@"%@",response);
}];
[uploadTask resume];

What am I doing wrong with the NSMutableData?

A second, and related question is: Is it worth using an objective-C lib curl wrapper at all?

Rambatino
  • 4,716
  • 1
  • 33
  • 56
  • Are you implementing the (void)URLSession:(NSURLSession *)session didReceiveChallenge: method? 403 could be related to this. – Xcoder Sep 01 '14 at 13:57
  • As in, I shouldn't be calling that delegate method? The only code I was running was what I posted here ( I guess there was no need to reference self in the delegate call): I'm not particularly sure what I should be doing with that delegate method however, either way it doesn't seem to do anything when i've just added it now. – Rambatino Sep 01 '14 at 15:19

1 Answers1

3
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://upload.uploadcare.com/base/"]];

    UIImage *image = [UIImage imageNamed:@"image.jpg"];
    NSData *imageData = UIImageJPEGRepresentation(image, 1.0);

    [request setHTTPMethod:@"POST"];

    NSString *boundary = @"unique-consistent-string";

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

    // post body
    NSMutableData *body = [NSMutableData data];

    // add params (all params are strings)
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=%@\r\n\r\n", @"UPLOADCARE_PUB_KEY"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n", @"demopublickey"] dataUsingEncoding:NSUTF8StringEncoding]];

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

    // add image data
    if (imageData) {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=file; filename=image.jpg\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:imageData];
        [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    }

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

    // setting the body of the post to the reqeust
    [request setHTTPBody:body];

    // set the content-length
    NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue currentQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

                               if (data.length > 0) {
                                   NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
                               }
    }];

http://nthn.me/posts/2012/objc-multipart-forms.html

https://gist.github.com/mombrea/8467128

Rusik
  • 239
  • 1
  • 11
  • Hi Rusik, it gives me a 403 when I use this when autostore is turned off and UPLOADCARE_STORE == 1: how do I store the file on the server when autostore is off? – Rambatino Sep 28 '14 at 12:13
  • Autostore — is an option to store files during uploading. You need to allow autostore in project settings to make it work. Regular store is request to REST API which can be done within 24 hours after uploading: https://uploadcare.com/documentation/rest/#file-store – homm Sep 29 '14 at 11:24