Servlet: response.setContentLength() slows download down

18,168

Perhaps because you're specifying a larger size than what is actually been sent to the response and the webbrowser basically get confused and is waiting for more data? You know, ZIP compresses files and reduces the final size.

Just don't specify the response's content length if you cannot efficiently calculate it beforehand. The servlet container will automatically send it with chunked encoding anyway. True, this has a little more overhead and leaves the webbrowser with an unknown download progress, but this doesn't require you to buffer the entire response in server's memory first so that you can get the proper final response content length.

If you really want to calculate the final response content length, you'd need to write it all to a ByteArrayOutputStream instead and then get the byte[] by its toByteArray() method. The real response content length is then the length of the byte[].

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
// ...

response.setContentLength(baos.size());
response.getOutputStream().write(bytes);

This is only more memory hogging because everything will be stored in server's memory first. If multiple users do this concurrently and the zip output is relatively large, then your server might risk to run out of memory sooner or later. As another alternative, you could write it using FileOutputStream to a temp file as created by File#createTempFile(), so that you can obtain its size by File#length() and use FileInputStream to stream it directly into the OutputStream of the response the usual way. This is only slower as you're basically transferring the bytes around twice.

Share:
18,168
Simon
Author by

Simon

Updated on June 11, 2022

Comments

  • Simon
    Simon almost 2 years
    private void downloadAllRelease(HttpServletRequest request,
            HttpServletResponse response) {
        LoginToken tok=getToken(request, response);
        int size = 0;
        try {
            ArrayList<Release> releases = manager.getReleases(tok.getUsername);
            ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
            for (int i=0; i<releases.size(); i++) {
                size += releases.get(i).getFile().length;
                out.putNextEntry(new ZipEntry(releases.get(i).getFilename()));
                out.write(releases.get(i).getFile());
                out.closeEntry();
            }
            response.setContentLength(size);
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition","attachment;filename=release.zip");
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    response.setContentLength() reeeeally slows downloads down.
    If I don't use It or put it after out.close() everything still works fine but downloads are muuuuch faster.
    Can someone explain me why and if it is necessary to use response.setContentLength()?

  • Palaniraja
    Palaniraja over 10 years
    i have an doubt to write a response to download file..how to redirect the page after download complete?
  • BalusC
    BalusC over 10 years
    @Palaniraja: Just press "Ask Question" button in right top to get an answer for that.