Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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] );
like image 513
tom Avatar asked Dec 08 '10 06:12

tom


3 Answers

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!?

like image 133
tom Avatar answered Nov 18 '22 09:11

tom


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];
like image 1
Akash Kava Avatar answered Nov 18 '22 11:11

Akash Kava


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.

like image 1
AechoLiu Avatar answered Nov 18 '22 09:11

AechoLiu