Search code examples
iosobjective-cfile-uploadnsurlsessionnsurlsessionuploadtask

Using NSURLSessionUploadTask fromFile, how to link the HTML input name with the file being uploaded?


I am wanting to upload a file to a server from an iOS device. I want to use the NSURLSessionUploadTask and I want the upload to get the content of the file being uploaded from a file.

The server is expecting to receive a file called "sightings.zip".

The HTML form used for the upload contains an input tag with name "fileBean" as per:

<input name="fileBean" type="file" />

I think I need to set up the request so that it contains the right "Content-disposition" information:

Content-Disposition: form-data; name="fileBean"; filename="sightings.zip"

but I have not idea how to do that based on the examples I can find, the questions on so and the Apple documentation.

My relevant code is given below.

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.allowsCellularAccess = YES;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[operationManager backgroundQueue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[GGPConstants urlFor:GGP_SEND_SIGHTINGS_PATH]];
[request setHTTPMethod:@"POST"];
[request setValue:@"identity" forHTTPHeaderField:@"Accept-Encoding"];
[request setValue:@"Content-Type" forHTTPHeaderField:@"application/zip"];
[request addValue:@"sightings.zip" forHTTPHeaderField:@"fileName"];

// How to get the value for the name and filename into the content disposition as per the line below?    
// Content-Disposition: form-data; name="fileBean"; filename="sightings.zip"

NSURLSessionUploadTask *uploadTask = [session
    uploadTaskWithRequest:request
    fromFile:myFileURL
    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
        } else {
            // Celebrate the successful upload...
        }
}];

In the past I have used AFNetworking's AFHTTPRequestSerializer, which supplies the input name when you are building the form data but that is not working for me for other reasons.

Any help would be appreciated.


Solution

  • I don't recommend the form-data type, because it is easy to get wrong. Better to use application/x-www-form-urlencoded, which is really trivial to construct. In that format, the body data basically looks like a GET request, but without the question mark, e.g.

    name=foo.jpg&data=[url-encoded data blob here]
    

    where the url-encoded data blob can be generated as described in Apple's docs with a couple of (__bridge_transfer NSString *) and (__bridge CFStringRef) bits added. :-)

    With that said, there's a decent example of multipart form data here on Stack Overflow already. Be careful to note that you add two extra hyphens to the front of the boundary when you actually use it, so if you specify "foo" as your boundary, then you'll have "--foo" between each part.