Les données POST volumineuses sont corrompues lors de l’utilisation de Django / PyISAPIe / IIS

Je rencontre un problème de données POST volumineuses (> 16 384 octets) lorsque j’utilise Django 1.2.3, PyISAPIe v1.1.0-rc4 et IIS 7.5.

Par exemple, lors de l’envoi d’env. 60 Ko de données de formulaire à l’aide de POST, voici ce qui se passe:

  • Le premier bloc de données POST de 16 Ko est correct
  • Le prochain bloc de 16 Ko est une répétition du premier bloc
  • Les 16 Ko suivants sont une autre répétition du premier bloc
  • Le rest (<16 Ko) est à nouveau correct

La partie intéressante est que lorsque vous utilisez content-type="multipart/form-data" , cela fonctionne bien.

En utilisant ces informations, j’ai localisé l’emplacement probable du bogue dans WSGIRequest._get_raw_post_data dans django \ core \ handlers \ wsgi.py, qui gère le content-type="multipart/form-data" séparément du paramètre par défaut (aucun type de contenu). ) Cas.

Les deux cas sont lus à partir de self.environ['wsgi.input'] , défini sur l’object PyISAPIe. La différence est que le cas par défaut semble se lire en morceaux de 16 Ko, alors que le gestionnaire multipart semble lire en morceaux de moins de 2 Go.

Je ne connais pas suffisamment C et l’interface Python pour que C puisse approfondir davantage, mais je suppose que le bogue est quelque part dans PyISAPIe dans la fonction ReadClient de ReadWrite.cpp.

Ma solution actuelle consiste à append content-type="multipart/form-data" aux formulaires pouvant générer plus de 16 Ko de données.

Est-ce que quelqu’un a aussi rencontré ce problème ou sait-il comment déterminer si le bogue est en fait dans PyISAPIe?

Je vous remercie!

Auteur PyISAPIe ici.

Ce problème a été résolu dans la révision 184 du référentiel mais pas dans la version téléchargeable, comme indiqué dans la liste de diffusion .

Il corrigeait un bogue déjà documenté qui, apparemment, n’avait pas retenu beaucoup d’attention, car de nombreux utilisateurs vérifiaient la source plutôt que de télécharger le paquet. Ou, c’est mon meilleur choix de toute façon; peu importe, je prévois de fournir une version téléchargeable du code fixe.

Merci d’avoir porté cela à mon attention afin que l’on me rappelle de maintenir les versions de ce projet dans un état opérationnel.

J’ai creusé un peu plus profondément et je pense avoir trouvé le problème.

Dans PyISAPIe \ Readwrite.cpp:

 PyISAPIe_Func(DWORD) ReadClient( Context &Ctx, DWORD Length, void *const Data ) { if ( !Length ) Length = Ctx.ECB->cbTotalBytes; if ( !Data ) // Return the size of the the data that would be read return min(Length, Ctx.ECB->cbTotalBytes); DWORD Ret, Total = 0; if ( Length > Ctx.ECB->cbAvailable ) { [...snip...] } else { memcpy(Data, Ctx.ECB->lpbData, Length); Ctx.ECB->cbTotalBytes -= Length; Ctx.ECB->cbAvailable -= Length; return Length; } 

Si la méthode est appelée à plusieurs resockets avec Length <= Ctx.ECB-> cbAvailable, elle semble toujours copier le début du tampon Ctx.ECB-> lpbData dans Data et ne pas supprimer ces données du tampon ou avancer un pointeur. Ce n’est que lorsque les données sont épuisées (cbAvailable == 0) que les nouvelles données sont correctement lues dans Data plus tard dans le code.

Vous ne savez toujours pas comment résoudre ce problème, mais au moins, je peux le contourner en lisant suffisamment de morceaux de données pour qu’un seul morceau puisse tout lire.