The fileupload package is well-architected, and a pleasure to use, but I ran
into a problem.  Attached is a test case servlet which repeats the problem with
the Jun 24, 2003 fileupload-1.0 release.

FileUploadBase.parseRequest runs out of memory when parsing a form with a large
number of inputs.  The cause seems to be DeferredFileOutputStream which
allocates a ByteArrayOutputStream per input, each of which preallocates a buffer
of length inMemoryThreshold.  The in memory threshold defaults to 10k, but if it
is made larger (> 1 M in our environment), then the vm quickly runs out of
memory.  Most of this memory is wasted since most files are ~5k, and almost all
non-file inputs are less than 1k.

I patched DeferredFileOutputStream to use a different underlying in memory
stream.  I don't really know why ByteArrayOutputStream uses a single byte[],
since you can't do random access on the underlying buffer anyway.
I think the patch is something that could be incorporated into the default file
upload implementation without any noticable change in performance.

If anyone's interested in the patch, should I send it to someone, or check it in
myself?  I've never contributed any code to apache before so I'm a little fuzzy
on process.

thanks,
   mike

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;

public class TestServlet extends HttpServlet {

  private DiskFileUpload fileupload;

  public void init(ServletConfig config) throws ServletException {
    fileupload = new DiskFileUpload();

    System.err.println("Using " + fileupload);

    long uploadMaxSize = 1 << 25; // in bytes = 32 MB
    int uploadThreshold = 1 << 24; // in bytes = 16 MB
    String uploadPath = new File(System.getProperty("java.io.tmpdir", "/tmp"),
                                 "uploads").toString();
    fileupload.setSizeMax(uploadMaxSize);
    fileupload.setSizeThreshold(uploadThreshold);
    fileupload.setRepositoryPath(uploadPath);
  }

  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws IOException {
    System.err.println("Handling get request " + req);
    long t1 = System.currentTimeMillis();

    // write out form
    resp.setStatus(200);
    resp.setContentType("text/html");
    PrintWriter out = resp.getWriter();
    out.println("<html><head><title>Test Servlet</title></head>");
    out.println("<body>");
    out.println("<h1>Test Servlet</h1>");
    out.println("<form method=\"post\" enctype=\"multipart/form-data\">");
    out.println("<p><input type=\"submit\"></p>");
    out.println("<p>File: <input type=\"file\" name=\"file\"></p>");
    for(int i = 0; i < 100; i++) {
      out.println("<p>Text: <input type=\"text\" name=\"text" + i + "\"></p>");
    }
    out.println("<p><input type=\"submit\"></p>");
    out.println("</form>");
    out.println("</body>");
    out.println("</html>");

    long t2 = System.currentTimeMillis();
    System.err.println("Handled get in " + (t2 - t1) + "ms");
  }

  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  throws IOException {
    // handle form
    System.err.println("Handling post request " + req);
    long t1 = System.currentTimeMillis();

    List items = null;
    if(FileUploadBase.isMultipartContent(req)) {
      try {
        System.err.println("Request is multipart content");
        items = fileupload.parseRequest(req);
        System.err.println("Got " + items.size() + " parts");
      } catch(FileUploadException ex) {
        IOException ioe = new IOException("Failed to parse multipart content");
        ioe.initCause(ex);
        throw ioe;
      } catch(OutOfMemoryError err) {
        err.printStackTrace();
        throw err;
      }
    } else {
      System.err.println("Request is not multipart content");
    }

    resp.setStatus(200);
    resp.setContentType("text/html");
    PrintWriter out = resp.getWriter();
    out.println("<html><head><title>Test Servlet</title></head>");
    out.println("<body>");
    out.println("<h1>Test Servlet</h1>");
    out.println("Submit Successful");

    if(items != null) {
      out.println("<table border=\"1\">");
      out.println("<tr><th>Field Name</th><th>Name</th><th>Form Field</th>" +
                  "<th>Text</th></tr>");
      for(int i = 0, n = items.size(); i < n; i++) {
        FileItem item = (FileItem) items.get(i);
        out.println("<tr valign=\"top\"><td>" + item.getFieldName() +
                    "</td><td>" + item.getName() + "</td><td>" +
                    item.isFormField() + "</td><td><pre>" + item.getString() +
                    "</pre></td></tr>");
      }
      out.println("</table>");
    }

    out.println("</body>");
    out.println("</html>");

    long t2 = System.currentTimeMillis();
    System.err.println("Handled post in " + (t2 - t1) + "ms");
  }

  public String getServletInfo() {
    return "TestServlet";
  }

} // TestServlet



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to