0

I am trying to fully implement a resumable file upload system in Java. The library I am using is resumable.js which sends chunks of a file to save as .part and then merge them together at the end. When I receive the POST request, in my doPost method I take the request, save it into a HttpServletRequestWrapper and then use that to get all the data I need. However, when saving the files as .part I end up with them being empty and have a size of 0 bytes.

I have checked and it seems that the data is all there, but I can't seem to get the data to save. Is there something that I implemented incorrectly?

Here is a small snippet of the code I use to do this task:

public void doPost(HttpServletRequest request, HttpServletResponse response) {
    try {
        HttpServletRequestWrapper wrapReq = new HttpServletRequestWrapper(request);
        BufferedReader reader = wrapReq.getReader();
        /**
        * Get some data from the BufferedReader
        */
        if(ServletFileUpload.isMultipartContent(wrapReq)){
            File mkd = new File(temp_dir);
            if(!mkd.isDirectory())
                mkd.mkdirs();

            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            Iterator<FileItem> iter = upload.parseRequest(request).iterator();
            OutputStream out;

            out = new FileOutputStream(new File(dest_dir));
            while(iter.hasNext()){
                try {

                    FileItem item = iter.next();
                    IOUtils.copy(item.getInputStream(), out);                       
                    logger.debug("Wrote file " + resumableIdentifier + " with chunk number "
                            + resumableChunkNumber + " to " + temp_dir);
                    out.close();
                } catch (FileNotFoundException fnfe) {
                    fnfe.printStackTrace();
                }
            }
        }
        tryCreateFileFromChunks(temp_dir, resumableFileName, resumableChunkSize, resumableTotalSize);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Where the tryCreateFileFromChunks() method just checks if all the parts are there and merges them. It isn't the problem. The .part files themselves are being stored empty.

So, did I handle this the wrong way? I've been struggling to get this working correctly.

Fasih Awan
  • 1,891
  • 4
  • 17
  • 24
  • 1
    There is at least one error. Your `out.close();` is inside the while loop, whereas you open the stream outside the loop. This must produce wrong results in case you `iter` contains more than one element. I'm not sure if this might solve your problem, but its definitely a bug... Hm, opening a `FileOutputStream` to a directory should fail as well (not sure), open it against the file and not just the directory. – home Jan 27 '13 at 20:19

1 Answers1

2

You shouldn't be using HttpServletRequestWrapper, nor be calling its getReader(). The request body can be read only once and you've to choose whether to use getReader() method, or getInputStream() method, or getParameterXxx() methods on the very same request and not mix them.

Apache Commons FileUpload uses internally getInputStream() to parse the request body. But if you've called getReader() or getParameterXxx() beforehand, then Apache Commons FileUpload will get an empty request body.

All with all, to fix your problem, just get rid of wrapReq altogether.

if(ServletFileUpload.isMultipartContent(request)){
    // ...

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • But all the information that I need I have to get from the `getReader()` such as the chunk size, file name, chunk number, etc. Is there another way I can get this information? It's not in the header, and calling `getParameterXxx()` doesn't get anything either. The only way I was able to get the data from the request payload was to call `getReader()` – Fasih Awan Jan 27 '13 at 20:36
  • All this data comes from [Resumable.js's](https://github.com/23/resumable.js) POST requests – Fasih Awan Jan 27 '13 at 20:37
  • 2
    I've never heard of `resumable.js`, but after a quick glance in its documentation it appears that it's actually sending a `multipart/form-data` request with all the mentioned information (chunk size, number, etc) as form data elements. So they are all available in `FileItem` iterator. You just have to check `item.isFormField()` if it's a form field or a file field the usual way. This is in detail elaborated in the "See also" link. Just do as if you're dealing with hidden input fields. – BalusC Jan 27 '13 at 20:46
  • Sorry for the late accept answer, I had to go to work to apply the changes – Fasih Awan Jan 28 '13 at 16:17