Membres inscrits :2359
Membres en ligne : 0
Invités en ligne : 3


|
Menu Snippets (navigation): |
Détails du snippet : [wxHTTP] : uploader un fichier texte avec une requête POST |
Informations sur l'auteur de ce snippet : | |

Hors ligne
| Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1390
Snippets: 25
Tutoriels: 6
|
Introduction / Description : | |
Bonjour à tous. En réponse à un commentaire de ce snippet, voici comment envoyer un fichier texte avec une requête POST en utilisant wxHTTP. Voici tout d'abord une description de ce qu'il faut faire. Dans une requête POST "classique" (ne contenant que des variables simples), on place les variables et leur contenu les uns à la suite des autres, comme ceci : NomDeLaVariable1=ValeurDeLaVariable1&NomDeLaVariable2=ValeurDeLaVariable2&NomDeLaVariable3=ValeurDeLaVariable3Pour envoyer un fichier, il en est tout autre. Il faut d'abord créer une chaîne de caractères servant de séparateur entre les différentes variables et qui sera nommée "boundary" dans la requête. Cette chaîne devra obligatoirement commencer par "--" lorsqu'elle sera utilisée comme séparateur (mais pas lorsqu'elle sera déclarée") et devra également être suivie de "--" la dernière fois qu'elle sera utilisée.. Le type de la requête (header "Content-type") n'est plus "application/x-www-form-urlencoded" mais "multipart/form-data; boundary=" suivi de la chaîne servant de séparateur Ensuite, pour chaque variable, il faut ajouter une ligne Content-Disposition: form-data; name="nom_de_la_variable" suivie de 2 retours à la ligne. Pour un fichier, il faut ajouter la même ligne qui devra également contenir le nom du fichier (et son extension), suivie d'un retour chariot, et d'une ligne indiquant le type mime, suivie des deux retours chariots: Content-Disposition: form-data; name="nom_de_la_variable"; filename="nom_du_fichier.extension" Content-Type: text/plainAprès cette ligne et ces 2 retours chariots, il reste à insérer le contenu de la variable, ou celui du fichier Il faut également ajouter une ligne vide avant d'insérer le dernier séparateur (en fin de requête) Par exemple, si l'on veut envoyer une variable " pseudo" dont la valeur est " Nom du gars", ainsi qu'une variable " message" qui est un fichier texte nommé " Fichier.txt" contenant " Coucou tout le monde", la requête serait :
Code:Content-type: multipart/form-data; boundary=mon_super_separateur_de_la_mort --mon_super_separateur_de_la_mort Content-Disposition: form-data; name="pseudo" Nom du gars --mon_super_separateur_de_la_mort Content-Disposition: form-data; name="message"; filename="Fichier.txt" Content-Type: text/plain Coucou tout le monde --mon_super_separateur_de_la_mort-- Et voici maintenant l'implémentation d'une telle méthode:
Code wxWidgets:// Le header pour la classe wxHTTP #include <wx/protocol/http.h> wxHTTP http; // La chaîne servant de séparateur pour chaque variable transmise // Normalement, il faut créer une chaîne avec des caractères aléatoires wxString sBoundary=_T("Customized_Boundary_from_wxWidgets"); // Le header servant à déclarer le type de requête POST http.SetHeader(_T("Content-type"),wxT("multipart/form-data; boundary=")+sBoundary); // Le wxString servant à stocker les données à envoyer wxString sBuffer=_T(""); // On ajoute une variable POST "normale" : wxString sName1=_T("pseudo"); wxString sValue1=_T("Nom du gars"); sBuffer.Append(wxString::Format(_T("--%s\r\n"),sBoundary.c_str())); sBuffer.Append(wxString::Format(_T("Content-Disposition: form-data; name=\"%s\"\r\n\r\n"),sName1.c_str())); sBuffer.Append(wxString::Format(_T("%s\r\n"),sValue1.c_str())); // On ajoute maintenant une variable "FILE" wxString sName2=_T("message"); wxString sFName=_T("Fichier.txt"); // Le contenu du fichier à envoyer est ici modélisé par un simple wxString wxString sValue2=_T("Coucou tout le monde"); sBuffer.Append(wxString::Format(_T("--%s\r\n"),sBoundary.c_str())); sBuffer.Append(wxString::Format(_T("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n"),sName2.c_str(),sFName.c_str())); sBuffer.Append(_T("Content-Type: text/plain\r\n\r\n")); sBuffer.Append(sValue2); sBuffer.Append(_T("\r\n")); // On peut continuer avec d'autres variables // Et à la fin, on remet le délimiteur précédé d'une ligne vide // et auquel on ajoute deux tirets sBuffer.Append(wxString::Format(_T("\r\n--%s--\r\n"),sBoundary.c_str())); // On place la requête dans le "PostBuffer" du wxHTTP http.SetPostBuffer(sBuffer); // Ensuite, c'est comme une requête POST classique // On mets le Timeout à 2 minutes (car par défaut, wxWidgets le met à 10 minutes) http.SetTimeout(120); // Le buffer qui va recevoir les données char szBuff[1025]; // Pour une page web, on va pouvoir la stocker dans un wxString wxString data=_T(""); // On essaye de connecter le wxHTTP : on ne peut se connecter qu'à un serveur // et non à une adresse complète du style http://www.wxwidgets.org/downloads if (http.Connect(_T("127.0.0.1"),80)) { if (wxInputStream *stream=http.GetInputStream(_T("/wxdev-fr/test-upload.php") ) ) { // On lit une partie des données disponibles stream->Read(szBuff,1024); while (stream->LastRead()) { // On s'assure que le texte téléchargé se termine bien // par un caratère zéro szBuff[stream->LastRead()]='\0'; // On fait la conversion si nécessaire data+= wxString::FromAscii(szBuff); // Et on essaie de lire la partie suivante stream->Read(szBuff,1024); } delete stream; } } txtResult->SetValue(data); // Vous pouvez maintenant faire ce que vous voulez anec le wxString "data"
Voilà , c'est tout. Cette méthode ne permet d'envoyer que des fichiers textes. En effet, wxHTTP ne peut prendre qu'un wxString comme PostBuffer. Il est donc impossible d'y placer des données binaires, car elles risquent fort d'être tronquées (j'ai essayé  ). Pour envoyer des fichiers binaires (images, archives, ...), il va vous falloir créer votre propre classe (dérivée de wxHTTP ou non), et utilisant, par exemple, un wxMemoryBuffer à la place d'un wxString pour stocker les données à envoyer. A noter également qu'un "Add On" de wxWidgets, nommé " wxHTTPEngine" permet l'envoi de tout type de données par la méthode POST. A l'heure actuelle, cette version ne marche qu'en Ansi. Pour l'utiliser en Unicode, il existe une version modifiée ici. @+ Xav'
xxltux (Membre)
Lieu: Montpellier
Inscrit le : 07-10-2007
Messages: 544
Snippets: 0
Tutoriels: 0
Site web
Hors ligne |
Heu faut pas les foutre en Mime64, ce qui reviens a ne chaine de caractére?
Dernière modification par xxltux (11-11-2007 01:28:35)
|
Itérer est humain, récurser est divin
|
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1390
Snippets: 25
Tutoriels: 6
Site web
Hors ligne |
Salut.
C'est pas "Mime64", mais "Base 64". Et non, ce n'est pas le cas. Le "Base 64" est, je crois, utilisé lorsque le site distant requiert une authentification, ou quelquechose comme ça....
@+ Xav'
|
Le nouveau portail wxWidgets francophone : www.wxdev.fr Ben en fait, vous y êtes déjà ... et effectivement, depuis le temps, ce n'est plus tellement nouveau....
|
patrick (Invité)
|
Avez vous esasyé avec un vrai fichier ??? Moi j'essaye d'uploader des images et ça rame à fond 100% de cpu.
je fais juste:
Code Cpp:wxString resultat; wxStringOutputStream outtext(&resultat); wxTransferFileToStream(_T("maphotos.JPG"),outtext);
ça marche très bien pour le download...fichier de 2GO => CPU environ 5% mais impossible d'uploader une photos de 4Mo sans avoir 100% de cpu.
à priori c'est GetInputStream
|
|
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1390
Snippets: 25
Tutoriels: 6
Site web
Hors ligne |
Salut.
patrick:Avez vous esasyé avec un vrai fichier ??? Moi j'essaye d'uploader des images et ça rame à fond 100% de cpu. Oui, j'ai fait l'essai : c'est pour ça que j'ai précisé (dans le titre et dans les explications finales) que cette méthode ne marche qu'avec un fichier texte.
Tu n'est pas sans ignorer qu'une chaîne de caractères se termine avec le caractère null (double, dans le cas d'Unicode). Or, Un fichier "binaire" (image, exécutable, ...) contient généralement plusieurs fois ces deux caractères nulls, ce qui fait que wxHTTP considère que la fin du fichier est atteinte, alors que le stream, lui attends encore des valeurs à transmettre.
J'ai même fait l'essai d'une classe dérivée de wxHTTP, et utilisant un wxMemoryBuffer pour stocker le "PostBuffer" à la place du classique wxString, mais ça n'a pas marché, car il faut réimplémenter toute la classe. Peut-être un de ces 4, quand j'aurais le temps.
Sinon, fais l'essai avec wxHttpEngine, car ça marche (si tu prends la bonne version )
Bonne chance, et @+ Xav'
|
Le nouveau portail wxWidgets francophone : www.wxdev.fr Ben en fait, vous y êtes déjà ... et effectivement, depuis le temps, ce n'est plus tellement nouveau....
|
patrick (Invité)
|
L'upload de fichier fonctionne très bien mais il est très gourmand en CPU. Je retrouve bien ma photo sur mon site web.
Je viens de vérifier avec ethereal. La connection avec wxHTTP se fait lors du GetInputStream. En effet les infos sont uploadées lors de l'appel de cette fonction.
A priori il y a un bug lors de l'envoi des paquets en socket ( 100% cpu ). Je viens d'installer libcurl l'upload fonctionne très bien sans utiliser de cpu.
Pour moi wxHTTP est buggé sur l'upload de fichier en post.
Je vais essayé de déclarer le bug chez wxWidget pour voir.
|
|
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1390
Snippets: 25
Tutoriels: 6
Site web
Hors ligne |
patrick:L'upload de fichier fonctionne très bien mais il est très gourmand en CPU. Je retrouve bien ma photo sur mon site web. Avec le code ci-dessus ? C'est bizarre; car j'ai fait l'essai avec un fichier jpeg, et je n'ai jamais pu uploader tout le fichier (il n'était pourtant pas très gros : 76Ko). Au final, le fichier uploadé faisait tout au plus 1Ko, et était tronqué au premier "double octet null".
patrick:Je viens de vérifier avec ethereal. La connection avec wxHTTP se fait lors du GetInputStream. En effet les infos sont uploadées lors de l'appel de cette fonction. Effectivement : la méthode "GetInputStream" appelle la méthode "SendRequest" qui, comme son nom l'indique, envoie les données au serveur.
patrick:A priori il y a un bug lors de l'envoi des paquets en socket ( 100% cpu ). Je viens d'installer libcurl l'upload fonctionne très bien sans utiliser de cpu.
Pour moi wxHTTP est buggé sur l'upload de fichier en post. Je pense que cette classe n'a en fait pas du tout été prévue pour ça à l'origine.
Je vais de mon côté essayer de re-coder une classe similaire (y'a du copier/coller dans l'air) pour que ça puisse marcher.
@+ Xav'
|
Le nouveau portail wxWidgets francophone : www.wxdev.fr Ben en fait, vous y êtes déjà ... et effectivement, depuis le temps, ce n'est plus tellement nouveau....
|
Menu Snippets (navigation): |
|