Envoi de données à partir de JavaScript: err eur "EOFError

Salut tout l’monde,

J’ai un problème que je ne parviens pas à résoudre. Je vous explique…

Pour le projet en cours, une extension Firefox a été développée. Son job
c’est de récupérer les images trouvées sur une page et de les envoyer
sur le serveur. Pour ce faire, le développeur utilise un objet
XMLHttpRequest et il poste les données sous forme de
multipart/form-data. Voici le code JavaScript pour l’envoi d’une des
images:

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;

var mis =
Components.classes[MULTI].createInstance(nsIMultiplexInputStream);

var fin =
Components.classes[FINPUT].createInstance(nsIFileInputStream);
fin.init(fileTmp, 0x01, 0444, 4);

var sheader = new String();

sheader += "\r\n" + "--" + BOUNDARY + "\r\n";
sheader += "Content-disposition:
form-data;name=\"page_url\"\r\n\r\n"+encodeURIComponent(pageUrl);

sheader += "\r\n" + "--" + BOUNDARY + "\r\n";
sheader += "Content-disposition:
form-data;name=\"img_url\"\r\n\r\n"+encodeURIComponent(imagesListArray[indiceArray[i]][5]);

sheader += "\r\n" + "--" + BOUNDARY + "\r\n";

sheader += "Content-disposition:
form-data;name=\"commentaires\"\r\n\r\n"+encodeURIComponent(commentArray[i]);

sheader += "\r\n" + "--" + BOUNDARY + "\r\n";

sheader += "Content-disposition:
form-data;name=\"page_title\"\r\n\r\n"+encodeURIComponent(pageTitle);
sheader += "\r\n" + "--" + BOUNDARY + "\r\n";

sheader += "Content-disposition:
form-data;name=\"filename\";filename=\"" + fileTmp.leafName + 

“”\r\n";
sheader += “Content-Type: application/octet-stream\r\n”;
sheader += “Content-Length: " + fileTmp.fileSize+”\r\n\r\n";

var hsis =
Components.classes[STRINGIS].createInstance(nsIStringInputStream);
hsis.setData(sheader, sheader.length);

var endsis =
Components.classes[STRINGIS].createInstance(nsIStringInputStream);
var bs = new String("\r\n--" + BOUNDARY + "--\r\n");
endsis.setData(bs, bs.length);
var buf =
Components.classes[BUFFERED].createInstance(nsIBufferedInputStream);
buf.init(fin, 4096);

mis.appendStream(hsis);
mis.appendStream(buf);
mis.appendStream(endsis);

var xmlr = new XMLHttpRequest();
xmlr.open("POST", urlServeur, true);
xmlr.setRequestHeader("Content-Type", "multipart/form-data;
boundary=" + BOUNDARY);
xmlr.onreadystatechange=function() { /* ici du code vérifiant le
statut pour voir si c'est bien passé */ }
xmlr.send(mis);

Pour ses tests, le développeur a écrit un script PHP qui récupère les
données envoyées et renvoie un code erreur. Ca fonctionne parfaitement.
Mais je souhaite l’intégrer complètement au projet et donc j’ai réécrit
son code en Ruby. J’appelle la méthode et là , l’extension me sort une
erreur 404 (xmlr.status = 404), comme quoi elle ne parvient pas Ã
joindre le serveur.

J’ai un peu fouiné dans les logs et j’ai trouvé ceci dans mongrel.log:

Wed Feb 21 13:30:15 +0100 2007: Error calling Dispatcher.dispatch
#<EOFError: bad content body>
/usr/lib/ruby/1.8/cgi.rb:983:in `read_multipart'
/home/web/projet.com/ftp/dev/config/../vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb:38:in
`initialize_query'
/usr/lib/ruby/1.8/cgi.rb:2274:in `initialize'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/cgi.rb:50:in
`initialize'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/rails.rb:76:in
`new'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/rails.rb:76:in
`process'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:580:in
`process_client'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:579:in
`each'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:579:in
`process_client'
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:686:in 

run' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:686:ininitialize’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:686:in
new' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:686:inrun’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:673:in
initialize' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:673:innew’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:673:in
run' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/configurator.rb:267:inrun’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/configurator.rb:266:in
each' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/configurator.rb:266:inrun’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/bin/mongrel_rails:127:in
run' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel/command.rb:211:inrun’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/bin/mongrel_rails:231

L’erreur qui m’emphe de traiter les données est donc: #<EOFError: bad
content body>. J’ai fouiné sur Google, pas moyen de trouver pourquoi ça
passe mal. J’ai modifié le code JavaScript pour qu’il n’envoie plus
l’image et n’envoie rien que des données basiques (l’url de la page,
l’url de l’image, etc), mais ça n’a rien changé. Bref, je suis un peu
coincé…

Avez-vous une idée? Que pourrais-je faire pour résoudre ce problème?

Bonne après-midi à tous,

Michael

Michael H. a écrit :

const nsIStringInputStream =
var sheader = new String();
sheader += "Content-disposition:
“"\r\n”;
var buf =
xmlr.onreadystatechange=function() { /* ici du code vérifiant le

process_client' /usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/lib/mongrel.rb:673:in each’
/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.4/bin/mongrel_rails:231
Bonne après-midi à tous,

Michael


Railsfrance mailing list
[email protected]
http://lists.rubyonrails.fr/mailman/listinfo/railsfrance

Salut,
Tu pourait nous joindre le dump exacte de ce que XMLHttpRequest
envoie ?

merci

loiseau gaetan wrote:

Salut,
Tu pourait nous joindre le dump exacte de ce que XMLHttpRequest
envoie ?

J’imagine qu’il s’agit de ceci (exactement entouré par les ++++
ci-dessous):

++++

–111222111

Content-disposition: form-data;name=“page_url”

http%3A%2F%2Fdmoz.org%2F

–111222111

Content-disposition: form-data;name=“img_url”

undefined

–111222111

Content-disposition: form-data;name=“commentaires”

–111222111

Content-disposition: form-data;name=“page_title”

ODP%20-%20Open%20Directory%20Project

–111222111

Content-disposition:
form-data;name=“filename”;filename=“1172066678008_0”

Content-Type: application/octet-stream

Content-Length: 1095

++++

Je ne suis pas certain qu’il soit possible de passer de donner
multipart/form-data via AJAX ??

Je me trompe peut-être.

Vincenzo Ruggiero wrote:

Je ne suis pas certain qu’il soit possible de passer de donner
multipart/form-data via AJAX ??

Le script PHP récupère parfaitement les données, donc c’est possible,
non?

Michael H. wrote:

Vincenzo Ruggiero wrote:

Je ne suis pas certain qu’il soit possible de passer de donner
multipart/form-data via AJAX ??

Le script PHP récupère parfaitement les données, donc c’est possible,
non?

J’utilisais des form_remote_tag avec des input type=“file”, il m’était
impossible de récupérer les data en utilisant le form_remote_tag.

En passant en form_tag pas de problème.

Je me trompe peut-être, à voir.

Le 22 févr. 07 à 10:35, Vincenzo Ruggiero a écrit :

En passant en form_tag pas de problème.

Je me trompe peut-être, à voir.

Sans avoir investigué des heures j’avais abouti à la même conclusion
que Vincenzo à savoir pas d’upload possible via XHR.

Le workaround pour faire du remote upload c’est la sousmission d’un
formulaire dans une iframe ce qui dans les fait à le même effet mais
est particulièrement pénible dans rails car pas vraiment compatible
avec response_to et RJS.

Renaud_______________________________________________
Railsfrance mailing list
[email protected]
http://lists.rubyonrails.fr/mailman/listinfo/railsfrance

Renaud Morvan a écrit :

Le workaround pour faire du remote upload c’est la sousmission d’un
formulaire dans une iframe ce qui dans les fait à le même effet mais
est particulièrement pénible dans rails car pas vraiment compatible
avec response_to et RJS.
Plus précisément, ce n’est pas vraiment compatible avec RJS et
Prototype/Scriptaculous. J’utilise de plus en plus jQuery parce qu’avec
Prototype/Scriptaculous je bute un peu trop souvent sur ce genre de
problèmes. Et justement, il existe un plugin pour jQuery (ajaxUpload)
avec lequel l’upload via la soumission d’un formulaire via une iframe
fonctionne très bien et de manière plutôt propre.

++

yk

Mon problème est réglé. Tout d’abord, j’ai du modifié le code
JavaScript:

var sheader = new String();

// sheader += “\r\n” + “–” + BOUNDARY + “\r\n”; // ANCIENNE LIGNE

sheader += “–” + BOUNDARY + “\r\n”; // NOUVELLE LIGNE

sheader += “Content-disposition:
form-data;name=“page_url”\r\n\r\n”+encodeURIComponent(pageUrl);

J’ai donc enlevé le “\r\n” du début.

Ensuite ça n’allait toujours pas, parce que dans cgi.rb, il y a un test
que voici:

/Content-Disposition:.* name="?([^";]*)"?/ni.match(head)

J’ai donc modifié les lignes incriminées:

// sheader += “Content-disposition:
form-data;name=“page_url”\r\n\r\n”+encodeURIComponent(pageUrl);
sheader += “Content-disposition:form-data;
name=“page_url”\r\n\r\n”+encodeURIComponent(pageUrl);

C’était subtil (une histoire de whitespaces mal placés)… Maintenant
les données sont bien récupérées par le contrôleur.

Ola everybody,

Bon, je vais peut-etre rendre la vie plus facile a certains. J’ai dans
mes
cartons un petit plugin qui fait fonctionner le rendu rjs sur l’upload
de
fichier par iFrame. C’est un plugin qui derive de responds_to_parent: (
http://sean.treadway.info/svn/plugins/responds_to_parent/) (Note: j’ai
maille son auteur mais il ne m’a jamais repondu).

Attention, je ne garantis rien, il marche chez moi car j’ai des besoins
assez simple. Mais bon vous avez les sources donc, a vous de jouer !


Utilisation:

1/ Vue:

<%= form_tag_with_fake_ajax_upload({ :action => ‘save’, :id => @my_model
},
{ :target => ‘uploadIframe’, :begin => “alert(‘Hello world !’” }) %>

<%= file_field ‘foo’, ‘file’ %>

<%= submit_tag “Save” -%>

<%= end_form_tag %>

Remarque: :target (qui est le nom d’une iFrame) n’est pas obligatoire.
En
fait, cela l’est dans le cas ou l’utilisateur utilise Safari ET que
l’application essaye par exemple d’effacer le form pour le remplacer par
une
nouvelle version.

2/ Controlleur:

def save

2 possibilites (c’est une ou l’autre pas les deux en meme temps :slight_smile:

render_rjs_after_upload :update do |page|
page.alert ‘Youpi ca marche !’
end

Ou

render_rjs_after_upload :action => ‘save’

execute save.rjs pour le rendu

end


Ou le trouver ? lafforgue.fr

Il y aurait pas mal de choses a ameliorer mais ce plugin remplira sa
tache
parfaitement dans 90% des cas. J’oubliais, les tests unitaires ne
marchent
pas, desole.

Did

Le 22/02/07, Yann K. [email protected] a écrit :