views:

47

answers:

1

I use three servlets to serve files for download:

  • ByteArrayDownloadServlet: used for small files, such as reports or files from database
  • FileDownloadServlet: used for small to large files
  • MultipleFileDownloadServlet: create a zip with the requested files and stream it

They are based in the following implementation: link text

I have received several complaints about corrupted downloads. The problem is that I can't simulate or find a pattern in the errors:

  • sometimes with large files
  • sometimes when the user requests more than one file to download and a zip file and is created dynamically
  • sometimes with smaller files, but that are being requested by many users simultaneously

In the post's mentioned above comments there are people reporting similar problems, but no solution. I also read a lot of threads from here and this the closer I got: link text

Has anyone went through similar problem or have some sample code that works?

Thanks, Felipe

@Override
@SuppressWarnings("unchecked")    
protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
{
    HttpSession session = request.getSession();
    List<File> selectedFileList = (List<File>) session.getAttribute("selectedFileList");

    if(selectedFileList == null)
    {
        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Lista de arquivos não informada");
        return;
    }

    response.reset();
    response.setContentType("application/zip");        

    response.setHeader("Content-Disposition", "attachment; filename=\""
        + "atualizacoes_"
        + new Date().getTime() + ".zip" + "\"");

    ZipOutputStream output = null;

    try
    {
        output = new ZipOutputStream(response.getOutputStream());

        for(File file : selectedFileList)
        {
            InputStream input = new FileInputStream(file);
            output.putNextEntry(new ZipEntry(file.getName()));                

            byte[] buffer = new byte[DownloadHandler.DEFAULT_BUFFER_SIZE];
            int length;
            while((length = input.read(buffer)) > 0)
            {
                output.write(buffer, 0, length);
            }

            output.closeEntry();
            input.close();
        }            

     output.finish();
     output.flush();
     output.close();
  }
  catch(Exception e) 
  {
      if(!(e instanceof ClientAbortException))
      {
          new ExceptionMail(getClass().getSimpleName(), e);
      }
    }
  finally
  {            
        session.removeAttribute("selectedFileList");        
  }
A: 

The most common causes for randomly corrupted downloads from a servlet is that the servlet is not threadsafe and/or that it is reading bytes as characters. Sharing request or session based data among requests in the same session or servletcontext is also a possible cause for this problem.

BalusC
Can you give more details on this?Thanks
FkJ
A servlet is not threadsafe when it is assigning request or session scoped data as a servlet instance variable which is been used within the method block. Streaming bytes should not be done using `Reader` or `Writer`.
BalusC
I have attached my multiple file download servlet. I don't use instance variables. Am I missing something?Thanks
FkJ
You're however sharing data among requests in the same session. Aren't the endusers invoking multiple downloads inside the same session? Every new request may change the session data which may in turn affect the still running requests in the same session.
BalusC
Good point. I concatenated a timestamp to the session attribute name to make it unique for every request. I'll watch how it will work for the next days.Thanks.
FkJ