0

I am playing around the HTML5 webkitdirectory recursive directory upload:

<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file_input" webkitdirectory="" directory="">
    <input type="submit">
</form>

On the server side I process it with apache-commons-fileupload 1.3.1 (Streaming API):

@WebServlet(urlPatterns = "/upload")
public class DirUploadServlet extends HttpServlet
{        
    @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        ServletFileUpload upload = new ServletFileUpload();

        response.setContentType(MediaType.TEXT_PLAIN);
        PrintWriter writer = response.getWriter();

        try
        {
            FileItemIterator iter = upload.getItemIterator(request);

            while (iter.hasNext())
            {
                FileItemStream item = iter.next();

                if (!item.isFormField())
                {
                    writer.println(item.getName());
                }
            }
        }
        catch (FileUploadException e)
        {
            throw new IOException(e);
        }
    }
}

This works well for directories without subdirs. However, if I try to select a directory which contains subdirectories, the request is sent properly, however on server side I get the following exception:

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:1005)
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.close(MultipartStream.java:943)
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.close(MultipartStream.java:922)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl$FileItemStreamImpl.close(FileUploadBase.java:866)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:1017)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.hasNext(FileUploadBase.java:1106)
    at DirUploadServlet.doPost(DirUploadServlet.java:45)

The request (from Ubuntu Chromium) seems to be legal for me:

------WebKitFormBoundaryMQ53uSzX0G6oZpWL
Content-Disposition: form-data; name="file_input"; filename="probadir/dir2/."
Content-Type: application/octet-stream


------WebKitFormBoundaryMQ53uSzX0G6oZpWL
Content-Disposition: form-data; name="file_input"; filename="probadir/file1"
Content-Type: application/octet-stream


------WebKitFormBoundaryMQ53uSzX0G6oZpWL
Content-Disposition: form-data; name="file_input"; filename="probadir/dir2/file2"
Content-Type: application/octet-stream


------WebKitFormBoundaryMQ53uSzX0G6oZpWL--

The error is the same from Google Chrome in Windows. IE and Firefox does not have this feature yet.

kavai77
  • 6,282
  • 7
  • 33
  • 48

1 Answers1

0

The problem here is not with the commons-fileupload but either with the request or with the servlet container itself. When I log out the request in binary form using Glassfish 3.1.2 and Servlet API, I receive this code:

------WebKitFormBoundary7AVw8qF0sdCpYB1P
Content-Disposition: form-data; name="files[]"; filename="probadir/dir2/."
Content-Type: application/octet-stream

\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\

etc. and 0 bytes till the end. That is why both the commons-fileupload API and the Multipart API from Servlet 3 (e.g. request.getPart()) throws an exception.

Now I thing that the only solution is not to use the standard HTML form submit, but submit the files separately with JS explained here: Keep Directory Structure When Uploading

kavai77
  • 6,282
  • 7
  • 33
  • 48