wxDev.fr, le portail francophone consacré à wxWidgets ! ( The french portal for wxWidgets )  
Esp. membre
Recheche rapide



Recherche avancée
Statistiques
Membres inscrits :2359

Membres en ligne : 0
Invités en ligne : 4

Valid XHTML 1.0 Transitional

Valid CSS2

Menu Snippets (navigation):
Pages: 1    Accueil » Snippets » Internet - Réseaux
» [wxHTTP] : uploader un fichier texte avec une requête POST
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: 1375
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=ValeurDeLaVariable3

Pour 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/plain


Aprè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:
Contenu du snippet :

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"
 
Explications finales :
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'
Commentaires
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: 1375
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à...
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: 1375
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à...
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: 1375
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à...
Menu Snippets (navigation):
Pages: 1    Accueil » Snippets » Internet - Réseaux
» [wxHTTP] : uploader un fichier texte avec une requête POST