Sending multipart request from iPhone to Ruby on Rails (RoR) server - iphone

I've searched for this issue and found similar problems but none like it.
I'm building a request manually
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:TEST_URL]];
[request setHTTPMethod:#"POST"];
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[request addValue:contentType forHTTPHeaderField:#"Content-Type"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=upload[jsondata]\r\n\n Content-Type: application/octet-stream\r\n\r\n", [dateFormatter stringFromDate:startDate]] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[json dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
When this request reaches the rails server, it understands Content-Disposition, Content-Type, but the JSON part of the body is captured as "ActionDispatch::Http::UploadedFile", meaning the server isn't understanding the JSON and is looking at it as if it was a file.
What am I doing wrong? Is this a problem with requests made from iOS devices and sent to Rails servers? Some sort of bug? I've already tried ASIHTTPRequest, with the same results.

I solved the problem with something incredibly simple. I had to remove
Content-Type: application/octet-stream
from the body and I had to add Connection: Keep-Alive to the request, like this:
[request setValue:#"Keep-Alive" forHTTPHeaderField:#"Connection"];
I tried it after listening to the request on the receiving computer using WireShark and noticing that the connection was set to close as default.

Related

Multi-Part HTTP Request through xcode

i want to upload image,video and audio files to a server. I have read this thread on the similar topic but wasn't able to understand completely the flow of the code. It would be great if you can suggest me some sample code or tutorial to start with. I am using the following code to connect without any media to the server
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *url =[[NSString alloc]initWithFormat:#"%#",[NetworkConstants getURL]];
NSURL *theURL =[NSURL URLWithString:url];
[url release];
NSMutableURLRequest *theRequest =[NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:0.0f];
[theRequest setHTTPMethod:#"POST"];
NSString *theBodyString = [NSString stringWithFormat:#"json1=%#&userID=%#",jsonObject,[GlobalConstants getUID]];
NSData *theBodyData = [theBodyString dataUsingEncoding:NSUTF8StringEncoding];
[theRequest setHTTPBody:theBodyData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (conn) {
NSLog(#"Successful in sending sync");
}
else {
NSLog(#"Failed Connection in sending sync");
}
[conn release];
It would be really convenient for me if anything could be done editing this part of code.
Any form of help would be highly appreciated.
Thanks in advance!!
Although it is very early to answer my own question but I got the solution so thought of adding it up here.
To the above code we just need the following modification
NSData *imageData = UIImageJPEGRepresentation(attachedImage.image, 90);
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[theRequest addValue:contentType forHTTPHeaderField:#"Content-Type"];
NSMutableData *theBodyData = [NSMutableData data];
[theBodyData appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[theBodyData appendData:[#"Content-Disposition: form-data; name= \"server_value_name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[theBodyData appendData:[yourString dataUsingEncoding:NSUTF8StringEncoding]];
//this appends the image data
[theBodyData appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[theBodyData appendData:[[NSString stringWithString:#"Content-Disposition: form-data; name=\"image\"; filename=\"1.jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[theBodyData appendData:[[NSString stringWithString:#"Content-Type: image/jpg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[theBodyData appendData:[NSData dataWithData:imageData]];
[theBodyData appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[theRequest setHTTPBody:theBodyData];
And the rest remains the same as in Question.
One just need to remember while sending a Multi-Part Request that all the parameters required by the server need to go with in the boundary and every parameter should be send in individual boundaries.
Hope this helps the others as well.
:)

HTTPS POST from iPhone using NSURLConnection hangs for certain filesize range

I'm using NSURLConnection to make an async HTTPS POST to our webservice to upload a jpg. It works fine most of the time.
But when the post body is between 196609 and 196868 bytes (inclusive), the connection hangs after the file has been uploaded 100% (didSendBodyData tells me that it's 100% sent). Then after 5 minutes, the connection times out with the message "The network connection was lost." Larger and smaller filesizes work. I've tested this by capping the filesize of the file that I add to the post body.
The content length is getting set correctly. See the code below.
The upload looks fine when I upload to netcat via HTTP. The entire body of the message gets through. But I suspect something's going wrong because of the SSL encryption, like it's buffering an SSL encrypted block frame.
Is there a bug in the iPhone's SSL code that makes it not upload the entire post body even though it's reporting that it is, or something else?
Here's the section where I set the content length and append the file to the multi-part POST body. You can see i'm capping the filesize manually, to test.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nsurl];
[request setHTTPMethod:#"POST"];
[request setTimeoutInterval:1];
[request addValue:#"close" forHTTPHeaderField: #"Connection"];
// Add headers and POST information
NSLog( #"Posting file." );
NSString *stringBoundary = [NSString stringWithString:#"0xKhTmLbOuNdArY"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",stringBoundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSMutableData *postBody = [NSMutableData data];
...
[postBody appendData:[[NSString stringWithFormat:#"--%#\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithString:#"Content-Disposition: form-data; name=\"uploadFile\"; filename=\"upload.jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithString:#"Content-Type: image/jpg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
NSLog( #"file size...%d", [uploadFile length] );
//[postBody appendData:uploadFile];
[postBody appendData:[NSData dataWithBytes: [uploadFile bytes] length: 196099]];
[postBody appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody];
[request setValue:[NSString stringWithFormat:#"%d", [postBody length]] forHTTPHeaderField:#"Content-Length"];
NSLog(#"Uploaded POST size: %d", [postBody length] );
Ah, I've found what the issue is. Connection: Keep-alive is being set, even though I set connection: close. How do I override this?? It looks like you can't!?
I have following code that is tested for 30-40 MB of files, and it never hangs. It looks almost similar to your code, however are you sure that its not your server side scrip that may be waiting for something?
url = [NSURL URLWithString:u];
NSData* d = [self data];
request = [NSMutableURLRequest requestWithURL:url];
[request setTimeoutInterval: 2000 ];
[request setHTTPMethod:#"POST"];
[request setValue:
[NSString stringWithFormat:#"multipart/form-data; boundary=%#", BOUNDRY]
forHTTPHeaderField:#"Content-Type"];
NSMutableData *postData =
[NSMutableData dataWithCapacity:[d length] + 512];
[postData appendData:
[[NSString stringWithFormat:#"--%#\r\n", BOUNDRY] dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:
[[NSString stringWithFormat:
#"Content-Disposition: form-data; name=\"%#\"; filename=\"file.bin\"\r\n\r\n", FORM_FLE_INPUT]
dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:d];
[postData appendData:
[[NSString stringWithFormat:#"\r\n--%#--\r\n", BOUNDRY] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postData];
I think you can try to remove this line of codes.
[request addValue:#"close" forHTTPHeaderField: #"Connection"];
It will tell the http server to close this connection. By the RFC 2616 (HTTP/1.1), servers and clients should maintain persistent connection.

Constructing a simple HTTP Post request to send a single image from iPhone

I'm trying to send a single image from my iPhone app to my Google App Engine Java server. On the server, I'm getting a FileUploadBase$InvalidContentTypeException, which is thrown when the request is not a multipart request. ServletFileUpload.isMultipartContent(req) is printing false. I'm trying to send an image, encoded as a jpeg, and a few other parameters, but im testing with just "name" and the image. There are a few fragmented sources of info online demonstrating how to take an image from the iPhone and post it to a GAE server. I'd like to document both ends of the process here.
Here's my objective-c code:
NSData *imageData = [NSData dataWithData: UIImageJPEGRepresentation(theImageView.image, 1.0f)];
NSURL *url = [NSURL URLWithString:#"http://myurl.com/myservlet"];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setTimeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithString:#"Content-Type: multipart/form-data; boundary=\"6G+f\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Disposition: form-data; name=\"name\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"whatever"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Disposition: form-data; name=\"myImage\" filename=\"ipodfile.jpeg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Type: image/jpeg\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(#"return %#",returnString);
I took most of the java code from here: How to upload and store an image with google app engine (java) . I'll post the complete solution once the objective-c problem is found. THANKS!!
Scrap all that code and start using ASIHTTPRequest for your http client needs. It's SO much easier and more powerful. I build highly server-interactive apps that include image uploads, and I haven't touched the native NSURLConnection interface in literally months.
That library has an ASIFormDataRequest object that handles all the fiddly little pieces of configuration for you. You literally load it up with data, fire it, and it works.
http://allseeing-i.com/ASIHTTPRequest/How-to-use

examples/tutorials iPhone post/upload request?

I am doing some uploading stuff in iphone this time. This is absolutely first time for me.
I have found some useful links and answers by googling and finding them on stackoverflow.
And I was able to upload an image by the following code :
NSData *imageData = UIImageJPEGRepresentation(imageView.image, 90);
NSString *urlString = #"server-url";
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc]init] autorelease];
[request setTimeoutInterval:60.0];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField:#"Content-Type"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Disposition: form-data; name=\"file\";filename=\"myfile.jpg\"\r\n"]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//NSString * dataLength = [NSString stringWithFormat:#"%d", [body length]];
//[request addValue:dataLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:body];
NSLog(#"%#",[[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil] encoding:NSUTF8StringEncoding]);
But I have lots of questions on the how the above code works like what is boundary and what is the format for it What is content disposition and other things as well .
I have googled a lot for understanding the format for a post request but found nothing then ready code If anyone knows some good tutorial or exmples on how a post request format is build in iphone then please provide so i can understand how the above code will work ?
you can look at the documentation on returning values from forms with POST here.
https://www.rfc-editor.org/rfc/rfc2388
like you said, the code works, this is a document explaining what you see and what it all means

iPhone : upload image to web aspx file

I have a little problem.
I have to upload a photo from my iPhone to a web server with POST Method but the server file is in aspx.
I tried my code with my server and PHP file : works well !
Now with aspx file : doesn't upload :(
I don't havec access to the .aspx .
Here is my iphone code :
NSData *imageData = UIImageJPEGRepresentation(imageView.image,70);
NSString *urlString = #"http://iphone.domain.net/upload_photos.aspx";
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"photo\"; filename=\"%#.jpg\"\r\n",[c nom]] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
I think the problem comes from the Content-Type or for my dataUsingEncoding: parameter.
Have you got and idea to solve it?
If you're not opposed to using a 3rd party library consider looking at ASIHttpRequest. It'll make your life so much easier:
http://allseeing-i.com/ASIHTTPRequest/
http://allseeing-i.com/ASIHTTPRequest/How-to-use
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
// Upload a file on disk
[request setFile:#"/Users/ben/Desktop/ben.jpg" withFileName:#"myphoto.jpg" andContentType:#"image/jpeg"
forKey:#"photo"];
// Upload an NSData instance
[request setData:imageData withFileName:#"myphoto.jpg" andContentType:#"image/jpeg" forKey:#"photo"];
normally, the boundary does not contain the --- when it's specified in the Content-Type. Apart from that, can't see anything unusual.
Try to upload it to the aspx server from the command line with curl. Once you've got that working, pass -v (verbose) or -i (include HTTP headers) to check exactly what is being sent, and then you can try to replicate that in Cocoa.