How to add form parameters to a NSURLSessionUploadTask - ios

I need to upload a file to a server and the request has to specify some form parameters. How can I do this with the NSURLSessionUploadTask? In other words, how can I send a multipart POST request.
cheers

When using NSURLSessionUploadTask, you don't call setHTTPBody on the NSMutableURLRequest (like we used to do with NSURLConnection), but rather you include this in the NSData or file passed to the NSURLSession method, uploadTaskWithRequest (or in the stream we supply for uploadTaskWithStreamedRequest).
In terms of creating the body of the request, itself, you have to do this yourself. Obviously, a framework like AFNetworking can greatly simplify this process.

https://github.com/pyke369/PKMultipartInputStream
This library can generate the multipart request pretty well.

Related

iOS re-routing requests w/ GCDWebServer (not redirecting)

I want to create a server on iOS with GCDWebServer, which will accept request to localhost, and then, draw the data from another url (a video file) and stream the data to the response. I intend to use plain NSURLConnection, and in the didReceiveData of the NSURLConnection callback, I want to pass this data to the GCDWebServerResponse.
I am having a hard time to figure out how can I keep the connection from a request open, so that I can initiate another request w/ NSURLConnection, and start serving data to the response.
Is there any way I can do that? Do I need to create a new subclass of GCDWebServerStreamedResponse?
Thank you in advance.
You don't need to subclass GCDWebServerStreamedResponse but simply instantiate it and use the GCDWebServerAsyncStreamBlock callback.
In the callback, create your NSURLConnection and have it run asynchronously. Then whenever new data is available (e.g. from -didReceiveData:), pass it through using the GCDWebServerBodyReaderCompletionBlock and when there is no more data available, pass an empty NSData.
See the "Advanced asynchronous version" in the GCDWebServer README for a similar concept.

Difference between multipart form upload and NSURLSession.uploadTaskWithRequest

Coming from the world of web programming, I'm pretty much comfortable with working with multipart form requests to upload files. However, in iOS, we have a thing called NSURLSession with the method uploadTaskWithRequest, which seems to be the method to call to do image uploads and the likes.
Can you explain the difference between the two approach, multipart form upload vs uploadTaskWithRequest? If I already have a backend that handle multipart form uploads, what kind of adjustments that I might need so that it support uploadTaskWithRequest as well?
The uploadTaskWithRequest simply sends the NSData, file, or stream as the body of the request. It doesn't do anything beyond that. It simply has the benefit that it can be used with background sessions.
So, if you have web service that is expecting multipart/form-data request, you have to build that request yourself (unless you use something like AFNetworking or Alamofire to do this for you). Once you've built that request, you can either use dataTaskWithRequest (having set the HTTPBody of the NSMutableURLRequest) or uploadTaskWithRequest (in which case you don't set HTTPBody, but rather provide it as a parameter to uploadTaskWithRequest).
By the way, a tool like Charles is very useful in these cases, letting you observe what's going on behind the scenes.
File Upload with multipart/form-data
The first approach using a multipart/form-data Content-type was originally defined in RFC 1867, then moved to the World Wide Web Consortium, which included it in the specification for HTML 4.0, where forms are expressed in HTML and where form values are sent via HTTP and electronic mail. When the form has been filled out by a user the form was sent to the server. This technique is widely supported and used by browsers and web servers.
However multipart/form-data can also be used to define form data which are presented in other representations than HTML. That is, you don't necessarily need a web browser or web server. The current specification which can be used by a wide variety of applications and transported by a wide variety of protocols is RFC 7578 (form IETF).
It must be mentioned, though, that the multipart/form-data content type was not always/is not without issues. It is quite complex by itself. Additionally, it uses/refers to a lot of other RFCs and - as a result of clearing things up - it and those which it depends on have been changed, obsoleted and updated quite frequently. Due to its complexity, serialisers and parsers are getting quite complicated, too and there's a lot of room for bugs and other issues.
NSURLSession uploadTaskWithRequest
How NSURLSession composes a request is not precisely documented. It certainly does not use a multipart/form-data content type, though.
For upload tasks, NSURLSession uses a POST request with a NSURLRequest as parameter which you can setup yourself. That is, you optionally can set the content type (for example text/plain; charset=utf-8), and other headers. NSURLSession can also derive an appropriate content type itself from the given content (file, stream or NSData). That is, we may say, it becomes a "simple" POST request. Due to less complexity, the request is less troublesome.
So, in order for your server to support an uploadTaskWithRequest where a file should be uploaded, it should simply support a POST request with some "simple" content type. That is, as opposed to a "file upload" with a multipart/form-data content type which contains the file name in a disposition header, the server would need to return the URL of the location where the resource (the file) has been written to.
Fortunately, it is quite easy to do a multipart/form-data POST request in the background, for example if you want to upload an image along with some other information.
First, create the NSMutableURLRequest in the same way like you would for a synchronous request (see for example POST multipart/form-data with Objective-C).
Then, write the body of the request to a file and supply it to the uploadTaskWithRequest method of the NSURLSession that you created with a backgroundSessionConfiguration:
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(
NSCachesDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:imageUUID];
[request.HTTPBody writeToFile:filePath atomically:YES];
NSURLSessionUploadTask *task = [urlSession uploadTaskWithRequest:request
fromFile:[NSURL fileURLWithPath:filePath]];
[task resume];
If you have multiple tasks and want to be able to distinguish them in the delegate callback, you can set a parameter (after you have created the request) with the NSURLProtocol class:
[NSURLProtocol setProperty:imageUUID
forKey:#"yourKeyForTheImageUUID"
inRequest:request];
and get it back in the callback like this:
- (void)URLSession:(NSURLSession *)session
task:(nonnull NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
NSString *imageUUID = [NSURLProtocol propertyForKey:#"yourKeyForTheImageUUID"
inRequest:task.originalRequest];

RestKit & AFNetworking store header on all responses

The API I am using requires me to send a signature string in the header of all my requests, in order to identify my session.
I get this signature from a header I read in the API's responses. The first call I make doesn't need the signature, but all subsequent requests do. The signature can change at any time, so I need to update my default header if I'm sent a new signature string.
Some of the calls I make use [RKObjectManager sharedManager], in some others I use AFNetworking directly using [RKObjectManager sharedManager].HTTPClient
What I would like to do is find a way to configure my underlying AFNetworking client so for every response that comes in I read the signature from the header and update my default header accordingly.
Any idea how to do this?

Library for multi-part form data request in iOS

I am trying to upload an image to a server with multipart form data. I was trying it with NSURLConnection and NSMutableURLRequest. But I couldn't get it work. Then I came across ASIHTTPRequest and its support for multipart form requests. But I understand that it is no longer being maintained. Does anyone know of a similar library that I can use?
You can start using AFNetworking. It's an awesome Library :
https://github.com/AFNetworking/AFNetworking

ASIHttpRequest call Restful web service?

Can ASIHttpRequest call Restful web service ? I knew that Restkit is good at it.
If no,any easy way to convert ?
Can we say that ASIHttpRequest is good at calling soap based web service ?
Thanks for your comments !
ASIHTTPRequest simply does a HTTP request. Nothing more, nothing less. Since REST is also just an HTTP request, you can use ASIHTTPRequest just fine with a restful web service. It doesn't do any parsing of the response, though, so if the response is JSON you still have to parse that yourself.
You can also use ASIHTTPRequest for SOAP but you have to construct the XML by yourself (or using some other library) and parse the XML response by yourself as well. For SOAP you may want to use http://sudzc.com/ instead.

Resources