InternetOpenUrl retourne seulement après l'intégralité de la réponse HTTP est téléchargé

Je suis en train d'écrire un fichier de téléchargement de l'utilitaire à l'aide de WinINET, et ont remarqué (surtout sur les gros téléchargements), que le WinINET InternetOpenUrl() appel renvoie uniquement après l'intégralité de la réponse HTTP a été téléchargé.

J'ai confirmé cela en utilisant le proxy Charles outil, ainsi que l'utilisation de WireShark, et a remarqué que le téléchargement est terminé entièrement et ce n'est WinINET informer mon code.

Certains simplifiée (synchrone) code:

hInt = InternetOpen(USER_AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG, 
                    NULL, NULL, 0);
DWORD dwRequestFlags = INTERNET_FLAG_NO_UI   //no UI please
            |INTERNET_FLAG_NO_AUTH           //don't authenticate
            |INTERNET_FLAG_PRAGMA_NOCACHE    //do not try the cache or proxy
            |INTERNET_FLAG_NO_CACHE_WRITE;   //don't add this to the IE cache

hUrl = InternetOpenUrl(hInt, szURL, NULL, 0, dwRequestFlags, NULL);
if (hUrl)
{
  //<only gets here after entire download is complete>

  InternetCloseHandle(hUrl);
}
InternetCloseHandle(hInt);

La documentation suggère que cela envoie la demande et les processus, les en-têtes de la réponse (pas termine le téléchargement), et alors on s'attend à exécuter par le biais d'un InternetReadFile() boucle jusqu'à ce qu'il retourne TRUE et dwNumberOfBytesRead est de 0.

À partir de MSDN

Fonction InternetOpenUrl: La fonction InternetOpenUrl analyse l'URL de la chaîne, établit une connexion au serveur, et prépare pour télécharger les données identifiées par l'URL. L'application peut ensuite utiliser InternetReadFile [...] pour récupérer les données d'URL.

InternetReadFile Fonction:
Pour s'assurer que toutes les données sont récupérées, une demande doit continuer à appeler le InternetReadFile fonction jusqu'à ce que la fonction renvoie TRUE, et la lpdwNumberOfBytesRead paramètre est égal à zéro.

J'ai essayé, à l'aide de la méthode asynchrone trop, et a remarqué la même chose. Plus précisément, le INTERNET_STATUS_RESPONSE_RECEIVED n'est envoyée au siège social de la méthode de rappel après le téléchargement est terminé. Ce qui signifie que ma client est seul en mesure de commencer à accéder aux données après le téléchargement est terminé.

Dans une veine similaire, j'ai mis en place une version qui utilise le WinHttp bibliothèque de trop, et a remarqué exactement les mêmes résultats.

Ce qui rend les choses difficiles quand il s'agit de délais d'attente. Si le téléchargement dépasse le délai d'attente (la valeur par défaut de 30 secondes par les regards de celui-ci), InternetOpenUrl() échoue.

J'ai donc deux questions:

Si c'est le comportement attendu de la WinInet et WinHttp bibliothèques, pourquoi la documentation suggèrent une boucle par le InternetReadFile() appel, pourquoi ne pas simplement lire l'intégralité de la mémoire tampon (après tout WinINET a déjà) ?

Je comprends offrant la possibilité puisque vous n'avez pas toujours envie d'allouer 150 MO morceaux de mémoire, mais l'excuse fournie est que vous ne savez pas quelle quantité de données est disponible... mais WinINET a déjà terminé le téléchargement.

Et pourquoi le faire paraître remarquablement comme le recv() méthode enveloppé si c'est juste une abstraction au-dessus d'un fichier temporaire, ou un fichier dans le cache IE (ou pire, de perdre un bloc de mémoire)?

Et que dois-je être le réglage de la durée du délai d'attente pour? Si je ne sais jamais comment grand les données avant son expiration, alors comment puis-je décider ce que pour définir la valeur de timeout?

Est-ce le comportement attendu, et si oui, est-il un moyen pour obtenir les données comme il est ruisselant?

Sur une connexion lente ou avec un fichier de grande taille, il est très concevable que beaucoup de travail qui peut être fait sur les données avant que le téléchargement est terminé. Dans un classique Berkley socket re-mise en œuvre du protocole HTTP, boucle par le recv() appel serait de me fournir les données comme elle vient, ce qui est finalement ce que j'ai besoin.

Oui je pourrais ré-écrire une implémentation à l'aide de simples prises, mais je préfère ne pas perdre de temps sur le soutien de l'ensemble de la spécification HTTP et SSL de cryptage, pour ne pas mentionner la prise en charge du proxy dans WinINET.

  • Vous avez vu le même comportement avec HttpOpenRequest > HttpSendRequest ?
  • Malheureusement, je n'ai, à la fois synchrone et asynchrone implémentations. HttpSendRequest soit des blocs comme InternetOpenUrl (sync), ou le INTERNET_STATUS_REQUEST_COMPLETE notification n'est envoyée qu'après la réponse HTTP est complètement téléchargé (async).
  • Quelque chose est motivé quelque part, j'ai utilisé le wininet bibliothèques à plusieurs reprises, et ils se comportent comme la documentation décrit. peut-être d'élargir votre dépannage à la wininet l'installation ou le contenu de la réponse?
  • Même pour moi, pour ce que sa vaut, HttpSendRequest doit retourner rapidement (sauf réseau de probs) à quel point vous pouvez commencer avec ReadFile
InformationsquelleAutor brianb | 2011-04-24