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]