Le téléchargement vers le Blobstore donne un tas Java OutOfMemoryError

Je fais un formulaire de téléchargement très simple vers mon application Google App Engine. Dans le code client GWT, j’ai quelque chose comme:

final FormPanel uploadForm = new FormPanel(); uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART); uploadForm.setMethod(FormPanel.METHOD_POST); uploadBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { blobstoreUploadURLService.getBlobstoreUploadURL("/banzai/process-pdf", new AsyncCallback() { @Override public void onFailure(Throwable caught) { // TODO Auto-generated method stub System.err.println("FAILURE DURING UPLOAD SERVICE"); } @Override public void onSuccess(Ssortingng result) { uploadForm.setAction(result); uploadForm.submit(); } }); } }); 

Et il utilise un new FileUpload() pour sélectionner le fichier. Lorsque je le teste, localement ou sur une instance déployée, le message d’erreur suivant apparaît dans les journaux:

 WARNING: Error for /_ah/upload/agdrYnNrYWFychsLEhVfX0Jsb2JVcGxvYWRTZXNzaW9uX18YAww java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2786) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:71) at javax.mail.internet.MimeMultipart.readTillFirstBoundary(MimeMultipart.java:316) at javax.mail.internet.MimeMultipart.parse(MimeMultipart.java:186) at javax.mail.internet.MimeMultipart.getCount(MimeMultipart.java:109) at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:135) at com.google.appengine.api.blobstore.dev.UploadBlobServlet.access$000(UploadBlobServlet.java:72) at com.google.appengine.api.blobstore.dev.UploadBlobServlet$1.run(UploadBlobServlet.java:100) at java.security.AccessController.doPrivileged(Native Method) at com.google.appengine.api.blobstore.dev.UploadBlobServlet.doPost(UploadBlobServlet.java:98) at javax.servlet.http.HttpServlet.service(HttpServlet.java:713) at javax.servlet.http.HttpServlet.service(HttpServlet.java:806) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:51) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938) 

Il est intéressant de noter que plusieurs personnes semblent avoir déjà rencontré ce problème auparavant (il suffit de regarder ce problème ici et vous en trouverez quelques autres sur Google), mais personne ne semble avoir la moindre idée de ce qui se passe, et certaines personnes suggèrent même qu’il s’agisse d’une application. La faute du moteur. Avant de sauter à de telles conclusions téméraires, je pensais que je demanderais d’abord ici 🙂

Et au cas où cela serait intéressant, voici les en-têtes HTTP de la tentative de téléchargement (un très petit fichier), capturés avec HTTP Live Headers.

     POST / _ah / upload / AMmfu6ZyyhSgz9uOR5VX4QBZeYADTB-aSejVvfGaogl3E_E8yPOLgtX9-0mob17IYfsaRZg-YP7aZrp1D4pDAwuKKm9CoNjeVx1eN2PwBro9x0PqXPeBLpQ / ALBNUaYAAAAATDFOaLPIvuEEhSS6F4HxMmf9xOb8lp0y / HTTP / 1.1
     Hôte: kbskaar.appspot.com
     Agent utilisateur: Mozilla / 5.0 (Macintosh; U; Intel Mac OS X 10.6; anglais, version: 1.9.2.6) Gecko / 20100625 Firefox / 3.6.6
     Accepter: text / html, application / xhtml + xml, application / xml; q = 0,9, * / *; q = 0,8
     Accept-Language: en-us, en; q = 0.5
     Accept-Encoding: gzip, deflate
     Jeu de caractères accepté: ISO-8859-1, utf-8; q = 0,7, *; q = 0,7
     Keep-Alive: 115
     Connexion: Keep-Alive
     Référent: http://kbskaar.appspot.com/

     Cookie: Nom = Wong;  Prénom = Ka% 20Man% 20Sophia;  Nom d'utilisateur = kmswong% 40uwaterloo.ca
     Type de contenu: multipart / form-data;  frontière = --------------------------- 168072824752491622650073
     Longueur du contenu: 57
         ----------------------------- 168072824752491622650073--



     Erreur de serveur interne HTTP / 1.1 500
     Serveur: serveur de téléchargement Date de création: 1 juillet 2010 15:26:59 (1278023219)
     Type de contenu: text / html;  jeu de caractères = UTF-8
     X-AppEngine-Estimated-CPM-US-Dollars: 0.375815 $
     Utilisation des ressources X-AppEngine: ms = 7103 cpu_ms = 16217 api_cpu_ms = 0
     Date: lundi, 5 juillet 2010 à 03h06 GMT
     Pragma: no-cache
     Expire le: vendredi, 1er janvier 1990 à 00h00 heure française
     Cache-Control: no-cache, no-store, must-revalidate
     Longueur du contenu: 3211
         -------------------------------------------------- --------

S’il vous plaît laissez-moi savoir si vous avez des idées. Merci!

D’accord, le problème incroyablement stupide s’est avéré que j’avais FileInput atsortingbut “name” sur l’élément FileInput du formulaire. Cela rend évidemment le stream résultant non parsable, ce qui entraîne un épuisement de la mémoire de l’parsingur MimeMultipart.

Même si le problème finissait par être le mien et qu’il était facile à résoudre, je le considère toujours comme un bogue dans AppEngine, car aucune erreur aussi simple ne devrait causer une erreur OutOfMemoryError et un crash; cela pourrait également être une source de vulnérabilités DOS simplement en créant des requêtes HTTP malveillantes. Je vais déposer un rapport de bug avec Google.

et assurez-vous d’append ceci dans votre formulaire

 enctype="multipart/form-data"