NSURLRequest properly format multipart/form-data - objective-c

I've created an NSURLRequest that's firing off requests OK. I've got it wired to requestbin, but instead of requestbin parsing the pertinent form data, it's seeing it as raw body.
I've got a working CURL command that does this correctly, and as far as I can tell both request raw bodies look the same -- I can't figure out what in the Obj-c I need to change to get those form parameters to work properly.
Here's the inspect link for the requestbin: http://requestb.in/1iszums1?inspect
Working CURL:
curl -X POST -H "Authorization: Bearer token" -H "X-ADN-Pretty-JSON: 1" -F "type=com.example.test" -F "content=#/Users/me/Desktop/test.jpg" "http://re
questb.in/1iszums1"
Obj-c
NSString* url = #"http://requestb.in/1iszums1";
UIImage* img = [UIImage imageNamed:#"test.jpg"];
NSData *imageData = UIImageJPEGRepresentation(img, 1.0f);
NSString* token = #"token";
NSString* name = #"test.jpg";
NSString* type = #"com.example.test";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:60];
[request setHTTPMethod:#"POST"];
NSString *boundary = #"------------------------------6c491b1c62c8";
// set Content-Type in HTTP header
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[request setValue:contentType forHTTPHeaderField: #"Content-Type"];
[request setValue:[NSString stringWithFormat:#"Bearer %#", token] forHTTPHeaderField:#"Authorization"];
[request setValue:#"1" forHTTPHeaderField: #"X-ADN-Pretty-JSON"];
// 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=\"type\"\r\n\r\n%#\r\n", type] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"content\"; filename=\"%#\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
// add image data
if (imageData) {
[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:#"%lu", (unsigned long)[body length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
NSString *responseBody = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"%# %#", response, responseBody);
}
}];

Not having tried it, my guess is that you are missing a couple of dashes on your boundary:
change
[body appendData:[[NSString stringWithFormat:#"%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
to
[body appendData:[[NSString stringWithFormat:#"--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
Its tough to keep all of the dashes figured out. If your boundary string as declared in the content type is "foo" then you will need to separate each part with "--foo" and end the whole form data with "--foo--"

Related

- connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: never call

I want to notify my user about the progress of the upload of some Mpeg 3 files. Just one.
but I get issue as I say in the title.
My upload code is here
- (NSString *) upload: (NSData*) postData {
NSString *str;
NSURL *url = [NSURL URLWithString:#"http://example.com/test.php"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
request.HTTPMethod = #"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]];
// add mp3 data
if (postData) {
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=%#; filename=audio\r\n", #"audioFormKey"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: audio/mpeg3\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:postData];
[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 *postLength2 = [NSString stringWithFormat:#"%lu", (unsigned long)[body length]];
[request setValue:postLength2 forHTTPHeaderField:#"Content-Length"];
NSLog(postLength2);
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(data.length > 0)
{
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(str);
}
}];
return str;
}
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
NSLog(#"bytes transfer %li" ,(long)bytesWritten);
}
Here the Log "bytes transfer" is never call.
Thanks a lot for support
A bit odd to be calling sendAsynchronousRequest: and then sendSynchronousRequest: in the completion handler?
In any case, you aren't configuring the URL connection to have a delegate and, thus, your delegate method is never called.
You'll need to allocated and instantiate the URLConnection and then configure it to use your object as the delegate. And it needs to conform to the NSURLConnectionDelegate protocol.

Parse REST API uploading binary image data in Objective-C

I am getting a 500 error back when trying to send image data to the REST API
NSMutableURLRequest *parseRequest = [NSMutableURLRequest requestWithURL:url];
[parseRequest setHTTPMethod:#"POST"];
[parseRequest setValue:#“*****” forHTTPHeaderField:#"X-Parse-Application-Id:"];
[parseRequest setValue:#“*****” forHTTPHeaderField:#"X-Parse-REST-API-Key:"];
[parseRequest setValue:#"image/png" forHTTPHeaderField:#"Content-Type:"];
NSLog(#"All Headers: %#",[parseRequest allHTTPHeaderFields]);
NSData *imageData = [[NSData alloc]initWithData:[NSData dataFromBase64String:data]];
[parseRequest setHTTPBody:imageData];
NSURLResponse *theResponse = NULL;
NSError *theError = NULL;
NSError *theJSONError = NULL;
NSData *theResponseData = [NSURLConnection sendSynchronousRequest:parseRequest returningResponse:&theResponse error:&theError];
NSString *responseString = [[NSString alloc]initWithData:theResponseData encoding:NSUTF8StringEncoding];
NSDictionary *dataDictionaryResponse = [NSJSONSerialization JSONObjectWithData:theResponseData options:NSJSONReadingAllowFragments error:&theJSONError];
NSLog(#“Url to send request: %#“,url);
NSLog(#“Response String: %#",responseString);
NSLog(#"Response Error: %#",theError);
This returns :
All Headers:
{
"Content-Type:" = "image/png";
"X-Parse-Application-Id:" = *****;
"X-Parse-REST-API-Key:" = *****;
}
Url to send request: https://api.parse.com/1/files/pic2.png
Response String: *HTML page with 500 error*
Response Error: (null)
I'm assuming that it doesn't like the binary data being passed as the HTTPBody but as I'm not getting any error messages back it's hard to tell what's going on. Making the same request with CURL works fine.
try like this
NSMutableURLRequest *parseRequest = [NSMutableURLRequest requestWithURL:url];
[parseRequest setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[parseRequest setHTTPShouldHandleCookies:NO];
[parseRequest setTimeoutInterval:30];
[parseRequest setHTTPMethod:#"POST"];
// 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", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"%#\r\n", [_params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
// add image data
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
if (imageData) {
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"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
[parseRequest setHTTPBody:body];
// set URL
[parseRequest setURL:requestURL];

how to send image to web service with objective c

How can I send a text and image parameters to a soap webservice? I have written a piece of code which does read the response from the web service. I have done this for learning purposes. But I have to modify my code to send image and string parameters. How can I do that?
this code just reads the response...
- (IBAction)buttonClick:(id)sender {
recordResults = FALSE;
NSString *soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<GetUserList xmlns=\"http://methodoor.com/checkupservice/\" />\n"
"</soap:Body>\n"
"</soap:Envelope>\n"];
//NSLog(soapMessage);
_lbl_result.text = soapMessage;
NSURL *url = [NSURL URLWithString:#"http://servicing2.rotanet.com.tr/service.asmx"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d", [soapMessage length]];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue: #"http://methodoor.com/checkupservice/GetUserList" forHTTPHeaderField:#"SOAPAction"];
[theRequest addValue: msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
webData = [[NSMutableData data] retain];
}
else
{
NSLog(#"theConnection is NULL");
}
//[nameInput resignFirstResponder];
}
Thanks to #XJones
Here's code to post an image to web server:
// create request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:30];
[request setHTTPMethod:#"POST"];
// 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)
for (NSString *param in _params) {
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", BoundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"%#\r\n", [_params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}
// add image data
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
if (imageData) {
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"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"];
// set URL
[request setURL:requestURL];

Objective-C Box 2.0 File Upload - Problems

I've been trying to get file upload working with Box for the past few days. I know I'm doing something wrong, but just can't see what it is.
I've reduced my code down as much as I possibly can, to just this:
// Configure the request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://api.box.com/2.0/files/data"]];
[request setHTTPMethod:#"POST"];
[request setValue:boxAuthString forHTTPHeaderField:#"Authorization"];
// Setu up the request
NSString *boundary = [NSString stringWithString:#"--PLEASEHELPMEGETTHISWORKING"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#\r\n",boundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Add the info and data for the file.
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Disposition:form-data;name=\"filename\";filename=\"testfile.txt\"\r\n"]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Type:text/plain\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Hello"] dataUsingEncoding:NSUTF8StringEncoding]];
// Add the info and data for the target folder.
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Disposition:form-data;name=\"folder_id\"\r\n\r\n"]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"0"] dataUsingEncoding:NSASCIIStringEncoding]];
// Close the body and set to the request
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding: NSUTF8StringEncoding]];
[request setHTTPBody:body];
// now lets make the connection to the web
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(#"%#", returnString);
But, I still get a return of:
{"type":"error","status":404,"code":"not_found","help_url":"http://developers.box.com/docs/#errors","message":"Not Found","request_id":"10130600215xxxxxxxxxxx"}
Please can someone help point me in the right direction, as when I use POSTMAN or cURL, I can get it to work - so it is obviously an issue with my code. I suspect it is something to do with the 'folder_id', but can't seem to diagnose the actual cause.
Fixed it. The problem was in my 'boundary' construction code. I'd got:
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#\r\n",boundary];
And should have had:
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
Spot the incorrect termination '\r\n'. Oh well. Only wasted about 4 hours on this. :-)

How to send JSON request to service with parameters in Objective-C

I'm creating a iPhone app, and im trying to figure out how to create a JSON request to the webservice that contains parameters. In Java this would look like this
HashMap<String, String> headers = new HashMap<String, String>();
JSONObject json = new JSONObject();
json.put("nid", null);
json.put("vocab", null);
json.put("inturl", testoverview);
json.put("mail", username); // something#gmail.com
json.put("md5pw", password); // donkeykong
headers.put("X-FBR-App", json.toString());
The header has to contain a JSON object and "X-FBR-App" before the service recognizes the request. How would this be implemented in Objective-C ?
USE Post method.try this
NSString *method = #"addProduct";
NSString *jsonstring=#"http://yourdomain.com/product_review_api/product-review.php?";
NSString *urlString = [NSString stringWithFormat:#"%#",jsonstring];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
NSMutableData *body = [NSMutableData data];
// image file
NSData *imageData = UIImageJPEGRepresentation( labelimage, 0.8);
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
// parameter method
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"method\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[method dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
// parameter categoryid
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"category_id\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[selectedID dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
// now lets make the connection to the web
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(#"%#",returnString);
NSDictionary *profile = (NSDictionary*)[returnString JSONValue];
NSLog(#"profile=%#", profile);
you can append all the parameters like this.
JSON isn't baked into iOS, but if you look at www.JSON.org there are a number of Objective-C frameworks that provide the required functionality. I have no experience with any of them so I can't make recommendations, but it is a good start to finding a solution.
Also look at this SO question post-data-through-json-webservices-in-iphone