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]