Attention : Le contenu de ces pages n'a pas été mis à jour depuis longtemps. Il est probablement obsolète pour Firefox 4.0/Gecko 4.0 et supérieur. Pour du contenu plus récent, allez consulter developer.mozilla.org.

Methodes requetes http

Une requête HTTP est une demande envoyée au serveur par le navigateur. Cela peut être une demande d'un contenu d'un fichier : page html, fichier quelconque... Mais cela peut ne pas aboutir à un retour de contenu. Il est simplement envoyé une commande au serveur.

Dans tout les cas, le navigateur récuperera un code de retour (les codes comme 404, 202 etc...)

Rappel sur les méthodes de requêtes HTTP

En schématisant, une requête HTTP contient deux parties :

  1. l'entête
  2. le corps

L'entête contient entre autre :

  • le type de la requête (GET, POST...)
  • le mime-type du corps de la requête
  • l'Url
  • etc..

Le corps de la requête contient des informations additionnelles. Leurs présences et leurs contenus dépendent du type de la requête.

Requête GET

La méthode GET est simple : on appelle juste une URL classique. Celle-ci peut contenir des paramètres, que le serveur/la page interprétera.

Exemple : http://monsite.com/page.php?param1=valeur1&param2=valeur2...

Les paramètres sont séparés par une perluette & et chacun est composé comme suit : nom_du_parametre=valeur_du_parametre.

En PHP, dans la page correspondante à l'url, on pourra récupérer ces informations dans le tableau global prédéfini $_GET.

Requête POST

En méthode POST, nous avons également des paramètres. Par contre, ceux-ci ne sont plus indiqués dans l'url, mais dans le corps de la requête. La façon dont ils sont stockés est la même que pour GET, c'est à dire nom_du_parametre=valeur_du_parametre et chacun d'eux séparé par une perluette.

Il faut spécifier également dans l'entête que le type du contenu est application/x-www-form-urlencoded.

En PHP, on pourra récupérer les paramètres dans le tableau $_POST.

Requête POST avec envoi de fichier

L'envois de fichiers fonctionne aussi avec la méthode POST mais necessite plusieurs arguments : # Le Content-Type qui doit être à "multipart/form-data" suivit d'une suite de charactères de délimitation. En effet, ce content-type signifie qu'il va y avoir plusieurs parties dans la corps de la requête et cette chaine permettra donc de les délimiter. Ce qui donnera au final le résultat suivant :Content-Type: multipart/form-data, boundary=3894641383813313890". A priori, on peut mettre n'importe quoi comme delimitateur (à confirmer) # Chaque partie est ensuite préfixée par une entête "Content-Disposition : form-data" et est séparée par "--delimiteur"

Plutôt que de continuer dans la théorie, je pense qu'un exemple sera plus parlant. Imaginons le formulaire html suivant :

	<form enctype="multipart/form-data" action="page.php" method="post">
		<input type="hidden" name="addfile" value="1">
		<input type="file" name="filename"/>
		<input type="submit" value="Add"/>
	</form>

Il s'agit d'un simle formulaire d'upload de fichier avec un parametre de type "hidden" en plus (addfile=1). Le corp de la requête HTTP sera le suivant: %%

content-Type: multipart/form-data, boundary=111222111\r\n

\r\n

  1. -111222111\r\n

Content-disposition: form-data;name="addfile"\r\n

\r\n

1\r\n

  1. -111222111\r\n

Content-disposition: form-data;name="filename";filename="nom_fichier"\r\n

Content-Type: application/octet-stream\r\n

Content-Length: taille_du_fichier\r\n

\r\n

...Contenu du fichier...

  1. -111222111--\r\n

Quelques petites remarques :

  • Les \r\n à la fin de chaques lignes sont très important.
  • J'utilise le type application/octet-stream comme type de fichier uploadé par facilité, il semblerai qu'il soit mieux de mêttre le bon type mime : text/plain, text/html etc ... (mais ca marche très bien avec application/octet-stream quelque soit le type de fichier)
  • La derniere ligne contient : --boundary--

Pour plus d'information sur l'upload de fichier en HTTP, voir le RFC 1867 : http://www.faqs.org/rfcs/rfc1867.html

Utilisation de l'objet XMLHttpRequest de mozilla

Dans Mozilla, il existe un objet XMLHttpRequest qui permet, comme son nom l'indique, de faire des requetes HTTP avec un serveur WEB. Nous alons voir comment une application XUL permet, en quelque sorte, d'émuler des liens et des formulaires html.

Petites remarques sur les permissions

Attention, ce type de requête demande certaines permissions et échoura si vous inserez ce code dans un fichier XUL et que vous le lancez tel quel (mais fonctionnera sans problème si l'application est dans un paquage XPI). Pour pouvoir passez outre, vous devez ajouter la (les) ligne(s) suivante(s) :

 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

Pour pouvoir utiliser l'opbjet XMLHTTPRequest.

 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

Pour pouvoir utiliser les objets XPCOM (seulement nécessaire pour l'envoi de fichier)

Cela fera apparaitre un dialogue de Mozilla vous demandant si vous permettez à ce script d'avoir les permission UniversalBrowserRead ou UniversalXPConnect. Voir http://books.mozdev.org/html/mozilla-chp(..) pour plus de renseignements sur les permissions de mozilla.

La méthode GET

Il s'agit du type de requête le plus facile à faire. Si vous connaissez un petit peu le PHP (ou d'autre langage du même type genre JSP), vous savez sans doute passer des parametres d'une page à l'autre en utilisant page.php?nom1=val1&nom2=val2 etc .... Le principe en XUL (enfin plutôt en Javascript puisqu'il s'agit de coder dans ce langage) est exactement le même.

Le code nécessaire est donc le suivant :

	var requete=new String("http://monsite.com/page.php?nom1=val1&nom2=val2");
	var xmlr = new XMLHttpRequest();
	xmlr.open("GET",requete,false);
	xmlr.send(null);

La méthode open() possède 5 paramètres :

;method:Le type de méthode HTTP à utiliser (GET ou POST) ;url: L'URL de destination (avec les paramètres GET) ;async: Si false, la méthode est bloquante send est bloquante et attendra la fin de la réponse du serveur. Dans le cas contraire, la méthode send retourne tout de suite et s'execute en tache de fond ;login:Le login si nécessaire (pour quel type d'authentification ?) ;password:Le mot de passe associé au login

La méthode send prend en paramètre le corp de la requete qui est inutile de renseigner dans le cas d'une requete GET.

La méthode POST

La méthode POST est un peu plus complexe et l'exemple qui suit permet d'émuler un formulaire html au moyen de l'objet XMLHttpRequest.

Soit le formulaire html suivant :

 <form action="page.php" method="post">
   <input type="hidden" name="createdir" value="1">
   <input type="text" name="dirname"/>
   <input type="submit" value="Create"/>
 </form>

Ce formulaire possède 2 paramètres qu'il va falloir envoyer dans le corp de la requête HTTP

 var requ=new String("createdir=1&dirname=valeur_du_champ");
 var xmlr = new XMLHttpRequest();
 xmlr.open("POST",
           "http://monsite.com?page.php
	    false)
 xmlr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
 xmlr.send(requ);

Les paramètres sont encodés de la même façon que pour la méthode GET, c'est à dire nom1=val1&nom2=val2 etc ....

Il est important de spécifier le Content-Type:application/x-www-form-urlencoded pour que le serveur web sache de quoi il s'agit.

Les paramètres seront donc disponible dans le tableau $_POST de PHP ou son équivalent dans d'autre langage.

La méthode POST avec envoi de fichier

Là ça devient du sport et il est important de bien respecter le protocole HTTP. Dans l'exemple qui suit, nous allons émuler le formulaire suivant :

 <form enctype="multipart/form-data" action="page.php" method="post">
   <input type="hidden" name="addfile" value="1">
   <input type="file" name="filename"/>
   <input type="submit" value="Add"/>
 </form>

Ce formulaire est composé d'un champ d'upload de fichier et d'un paramètre de type hidden. Reportez vous au chapitre précédant pour connaitre la requète exacte que l'on va devoir envoyer.

Petites remarques préalables

Je n'ai pas détailler la méthode send mais sachez que celle-ci accepte plusieurs type de paramètres :

  • Une chaine de caractères (comme utilisé dans l'exemple précédant)
  • Un DomDocument (j'imagine qu'il sagit d'un document XML)
  • Un InputStream <- C'est celui là qui nous interesse

Le but du jeux va donc d'être de créer notre requête en mettant tout dans un InpoutStream.

Marche à suivre

  1. Créer un MultiplexInputStream qui est un flux composé d'autre flux (un container de flux en quelque sorte).
  2. Recupérer un flux de fichier (FileInputStream) et le mettre dans un flux bufferisé (BufferedInputStream). J'ignore pourquoi il faut le mettre dans un BufferedInputStream mais c'est le seul que je suis arrivé à faire fonctionner avec un fichier de type binaire. BinaryInputStream ne fonctionne pas et StringInputStream ne permet que d'envoyer des fichiers de type texte.
  3. Créer un flux de type chaîne de caractères (StringInputStream) dans lequel nous allons mêttre les entêtes spécifique à chaque partie du message et le paramètre de type hidden.
  4. Créer un autre flux de type chaîne de caractères qui va contenir la fin de la requête.
  5. Ajouter les 3 flux dans le MultiplexInputStream
  6. Préparer la requète avec la les entêtes nécéssaires.
  7. Prier
  8. Envoyer la requête

Je part du principe que vous savez créer des objets XPCOM en javascript et que vous avez déja un objet de type 'File'. Une façon simple d'en obtenir un est d'utiliser l'objet FilePicker (boite de dialogue de séléction de fichier).

Source

 const BOUNDARY="111222111"; //ce qui va nous servir de délimiteur
 const MULTI="@mozilla.org/io/multiplex-input-stream;1";
 const FINPUT = "@mozilla.org/network/file-input-stream;1";
 const STRINGIS="@mozilla.org/io/string-input-stream;1";
 const BUFFERED="@mozilla.org/network/buffered-input-stream;1";
 const nsIMultiplexInputStream=Components.interfaces.nsIMultiplexInputStream;
 const nsIFileInputStream=Components.interfaces.nsIFileInputStream;
 const nsIStringInputStream=Components.interfaces.nsIStringInputStream;
 const nsIBufferedInputStream = Components.interfaces.nsIBufferedInputStream;
 // 1
 var mis=Components.classes[MULTI].createInstance(nsIMultiplexInputStream);
 //2
 var fin=Components.classes[FINPUT].createInstance(nsIFileInputStream);
 fin.init(fic,0x01,0444,tmp); //fic est un objet de type fichier
 var buf=Components.classes[BUFFERED].createInstance(nsIBufferedInputStream);
 buf.init(fin,4096);
 //3
 var hsis=Components.classes[STRINGIS].createInstance(nsIStringInputStream);
 var sheader=new String();
 sheader+="\r\n";
 sheader+="--"+BOUNDARY+"\r\nContent-disposition: form-data;name=\"addfile\"\r\n\r\n1";
 sheader+=\r\n"+"--"+BOUNDARY+"\r\n"
 sheader+="Content-disposition: form-data;name=\"filename\";filename=\""+fic.leafName+"\"\r\n";
 sheader+="Content-Type: application/octet-stream\r\n";
 sheader+="Content-Length: "+fp.file.fileSize+"\r\n\r\n";
 hsis.setData(sheader,sheader.length);
 //4
 var endsis=Components.classes[STRINGIS].createInstance(nsIStringInputStream);
 var bs=new String("\r\n--"+BOUNDARY+"--\r\n");
 endsis.setData(bs,bs.length);
 //5
 mis.appendStream(hsis);
 mis.appendStream(buf);
 mis.appendStream(endsis);
 //6
 var xmlr = new XMLHttpRequest();
 xmlr.open("POST","http://monsite.com/page.php",false);
 xmlr.setRequestHeader("Content-Length",(mis.available()-2));
 //Je ne sais pas pouquoi -2, je doit faire une erreur quelque part
 xmlr.setRequestHeader("Content-Type","multipart/form-data, boundary="+BOUNDARY);
 //7 :)
 //8
 xmlr.send(mis);

En théorie (et en pratique chez moi), cela devrai fonctionner et le fichier devrai être envoyé.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.