2010-12-08 62 views
5

J'utilise NSURLConnection pour effectuer un POST HTTPS asynchrone sur notre service web pour télécharger un fichier .jpg. Cela fonctionne très bien la plupart du temps.HTTPS POST à ​​partir de l'iPhone en utilisant NSURLConnection se bloque pour certaines plages de fichiers

Mais lorsque le corps du message est compris entre 196609 et 196868 octets (inclus), la connexion se bloque une fois que le fichier a été téléchargé à 100% (didSendBodyData indique qu'il est envoyé à 100%). Ensuite, après 5 minutes, la connexion expire avec le message "La connexion réseau a été perdue". Les filesizes plus grandes et plus petites fonctionnent. J'ai testé cela en plafonnant la taille du fichier que j'ajoute au corps du message.

La longueur du contenu est définie correctement. Voir le code ci-dessous.

Le téléchargement semble très bien lorsque je télécharge sur netcat via HTTP. Le corps entier du message passe à travers. Mais je soupçonne que quelque chose ne va pas en raison du cryptage SSL, comme s'il s'agissait d'un cadre de bloc crypté SSL.

Y a-t-il un bogue dans le code SSL de l'iPhone qui empêche le téléchargement de tout le corps du message, même si c'est un rapport, ou quelque chose d'autre?

Voici la section dans laquelle je définis la longueur du contenu et j'ajoute le fichier au corps POST multi-parties. Vous pouvez voir que je plafonne la taille du fichier manuellement, pour tester.

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]); 

Répondre

1

J'ai le code suivant qui est testé pour 30-40 Mo de fichiers, et il se bloque jamais. Il semble presque similaire à votre code, mais êtes-vous sûr que ce n'est pas votre script côté serveur qui peut-être attendre quelque chose?

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]; 
+0

Je pensais que mon code ne serait jamais pendu non plus. La plupart des photos fonctionnent. Mais ensuite j'ai pris une photo qui s'est coincée. Je n'ai jamais eu de réponse quand la photo était de cette taille. Alors j'ai testé la taille de haut en bas, et j'ai trouvé ces limites. Je n'ai trouvé aucune autre région à l'origine de ce problème. Oui, il semble que notre serveur attende la demande complète avant de donner quoi que ce soit, et pense qu'il ne reçoit pas la demande complète. C'est vraiment étrange. – tom

+0

Eh bien, une condition est que la limite incluant les tirets (-) et les caractères de nouvelle ligne, doit être unique et ne doit pas apparaître à l'intérieur des données. –

1

Je pense que vous pouvez essayer de supprimer cette ligne de codes.

[request addValue:@"close" forHTTPHeaderField: @"Connection"]; 

Il indiquera au serveur http de fermer cette connexion. Par le RFC 2616 (HTTP/1.1), les serveurs et les clients doivent maintenir une connexion persistante.

+2

En fait, il s'avère que c'est le problème exact. l'iPhone ignore cet en-tête de fermeture et le place à keep-alive. avec keep-alive, il brise notre serveur. avec près, ça marche. comment puis-je remplacer la connexion nsurl pour accepter mon paramètre de fermeture? – tom

+0

Je lis le rfc2616 récemment. Et le document dit, ce champ d'en-tête "Connexion" avec "fermer" fermera la connexion. Peut-être que vous pouvez envoyer une demande uniquement avec cet en-tête "close" lorsque vous avez terminé le téléchargement. – AechoLiu

+0

Je me souviens de certains messages dans SO dit que le setHTTPBody va modifier certains paramètres de connexion. Par exemple, après setHTTPBody, le délai deviendra 75 secondes. Peut-être que vous pouvez définir ce headerField après avoir appelé setHTTPBody. – AechoLiu

3

Ah, j'ai trouvé quel est le problème. Connexion: Keep-alive est en cours de définition, même si j'ai défini la connexion: close. Comment puis-je remplacer cela ?? On dirait que tu ne peux pas !?