Search code examples
objective-ccurluploadnsmutabledatauploadcare

cURL upload photo command in NSMutableURLRequest format


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 "[email protected]" 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?


Solution

  •     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