上传到Blobstore会产生一个Java堆OutOfMemoryError [英] Uploading to Blobstore gives a Java heap OutOfMemoryError

查看:108
本文介绍了上传到Blobstore会产生一个Java堆OutOfMemoryError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的Google App Engine应用程序做一个非常简单的上传表单。在客户端GWT代码中,我有这样的东西:

  final FormPanel uploadForm = new FormPanel(); 
uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadForm.setMethod(FormPanel.METHOD_POST);
$ b $ uploadBtn.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event){
blobstoreUploadURLService.getBlobstoreUploadURL(/ banzai / process-pdf ,new AsyncCallback< String>(){

@Override
public void onFailure(Throwable caught){
// TODO自动生成的方法存根
系统。 err.println(FAILURE DURING DUPING SERVICE);
}

@Override
public void onSuccess(String result){$ b $ uploadForm.setAction(result);
uploadForm.submit();
}

});
}
});

它使用新的FileUpload()选择文件。当我在本地或部署的实例上测试它时,我在日志中看到以下错误:

 警告: / _ah / upload / agdrYnNrYWFychsLEhVfX0Jsb2JVcGxvYWRTZXNzaW9uX18YAww java.lang.OutOfMemoryError:java.util.Arrays.copyOf处的Java堆空间
(Arrays.java:2786)$ 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)
com.google.appengine.api.blobstore.dev.UploadBlobServlet $ 1.run(UploadBlobServlet.java:100)
在java.security.AccessController.doPrivileged(Native Meth od)
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)
在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。
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)
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)
在org.mortbay.jetty.HttpConnection $ RequestHandler.content(HttpConnection.java:938)

足够有趣,以前有几个人似乎遇到了此问题(请参阅这个问题在这里,你可以在Google上找到更多),但似乎没有人知道为什么会发生这种情况,有些人甚至认为这是App Engine的错。在我跳到这样粗糙的结论之前,我想我会先问这里:)

如果有趣的话,这里是试图上传的HTTP标头小文件),与HTTP实时头捕获。

 
POST / _ah /上传/ AMmfu6ZyyhSgz9uOR5VX4QBZeYADTB-aSejVvfGaogl3E_E8yPOLgtX9-0mob17IYfsaRZg-YP7aZrp1D4pDAwuKKm9CoNjeVx1eN2PwBro9x0PqXPeBLpQ / ALBNUaYAAAAATDFOaLPIvuEEhSS6F4HxMmf9xOb8lp0y / HTTP / 1.1
主机:kbskaar.appspot.com
用户代理:Mozilla / 5.0(Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.6)Gecko / 20100625 Firefox / 3.6 .6
Accept: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
Accept-Charset:ISO-8859-1,utf-8; q = 0.7,*; q = 0.7
Keep-Alive:115
连接:keep-alive
Referer:http://kbskaar.appspot.com/

Cookie:姓氏= Wong;姓名=嘉%20Man%20Sophia;用户名= kmswong%40uwaterloo.ca
内容类型:multipart / form-data; boundary = --------------------------- 168072824752491622650073
Content-Length:57
------- ---------------------- 168072824752491622650073--



HTTP / 1.1 500内部服务器错误
服务器:上传服务器建于2010年7月1日15:26:59(1278023219)
Content-Type:text / html; charset = UTF-8
X-AppEngine-Estimated-CPM-US-Dollars:$ 0.375815
X-AppEngine-Resource-Usage:ms = 7103 cpu_ms = 16217 api_cpu_ms = 0
Date:Mon ,05 Jul 2010 03:06:00 GMT
Pragma:no-cache
过期时间:1990年1月1日星期五00:00:00 GMT
Cache-Control:no-cache,no- store,must-revalidate
Content-Length:3211
-------------------------------- --------------------------

请让我知道你是否有任何想法。谢谢!

解决方案

好的,所以这个令人难以置信的愚蠢问题竟然是我遗漏了name属性 FileInput 表单的元素。这显然使得结果流不可解析,这导致MimeMultipart解析器耗尽内存。



即使问题最终成为我的,并且易于修复,我仍然考虑到这是AppEngine中的一个错误,因为这种简单的错误不会导致OutOfMemoryError和崩溃;这也可能是仅仅通过制作恶意HTTP请求而导致的DOS漏洞的来源。我将向Google提交一份错误报告。


I'm doing a very simple upload form to my Google App Engine application. In the client GWT code I have something like:

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<String>() {

                @Override
                public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    System.err.println("FAILURE DURING UPLOAD SERVICE");
                }

                @Override
                public void onSuccess(String result) {
                    uploadForm.setAction(result);
                    uploadForm.submit();
                }

            });
        }
    });

And it uses a new FileUpload() to select the file. When I test it, either locally or on a deployed instance, I get the following error in the logs:

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)

Interestingly enough, several people seem to have run into this issue before (just look at this issue here, and you can find a few more on Google) but nobody seems to have any idea why it's happening, and some people are even suggesting it's App Engine's fault. Before I jumped to such rash conclusions, I thought I'd ask here first :)

And in case it's interesting, here's the HTTP headers of the attempted upload (a very small file), captured with HTTP Live Headers.

    POST /_ah/upload/AMmfu6ZyyhSgz9uOR5VX4QBZeYADTB-aSejVvfGaogl3E_E8yPOLgtX9-0mob17IYfsaRZg-YP7aZrp1D4pDAwuKKm9CoNjeVx1eN2PwBro9x0PqXPeBLpQ/ALBNUaYAAAAATDFOaLPIvuEEhSS6F4HxMmf9xOb8lp0y/ HTTP/1.1
    Host: kbskaar.appspot.com
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
    Accept: 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
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 115
    Connection: keep-alive
    Referer: http://kbskaar.appspot.com/

    Cookie: Lastname=Wong; Firstname=Ka%20Man%20Sophia; Username=kmswong%40uwaterloo.ca
    Content-Type: multipart/form-data; boundary=---------------------------168072824752491622650073
    Content-Length: 57
        -----------------------------168072824752491622650073--



    HTTP/1.1 500 Internal Server Error
    Server: Upload Server Built on Jul 1 2010 15:26:59 (1278023219)
    Content-Type: text/html; charset=UTF-8
    X-AppEngine-Estimated-CPM-US-Dollars: $0.375815
    X-AppEngine-Resource-Usage: ms=7103 cpu_ms=16217 api_cpu_ms=0
    Date: Mon, 05 Jul 2010 03:06:00 GMT
    Pragma: no-cache
    Expires: Fri, 01 Jan 1990 00:00:00 GMT
    Cache-Control: no-cache, no-store, must-revalidate
    Content-Length: 3211
        ----------------------------------------------------------

Please let me know if you have any ideas. Thanks!

解决方案

Okay, so the incredibly silly problem turned out to be that I had left out a "name" attribute on the FileInput element of the form. This evidently makes the resulting stream unparseable, which causes the MimeMultipart parser to run out of memory.

Even though the problem ended up being mine, and was easily fixable, I still consider this a bug in AppEngine because there's no way such a simple mistake should cause an OutOfMemoryError and crash; this could also be a source of DOS vulnerabilities just by crafting malicious HTTP requests. I'll file a bug report with Google.

这篇关于上传到Blobstore会产生一个Java堆OutOfMemoryError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆