loupTerawatt
loupTerawatt

Reputation: 11

Corrupted Zip File , sent to the client side , java ee

I'm currently developping on a webserver for my company , and i'am facing a corrupted zip file problem. At the end of a servlet. Here's the function header called at the very end of the servlet.

sendFile(directory, "s" + this.optimizerId + "-" + this.optimizerName + "-" + start.toDate(Defs.DB.DATE_PATTERN) + "-" + end.toDate(Defs.DB.DATE_PATTERN), FileExtension.NONE, ContentType.ZIP, response);

Here is the first send File function ...

public default void sendFile(File file, String fileName, FileExtension extension, ContentType type, HttpServletResponse response) {
    if(type == ContentType.ZIP) {
        String[] files = file.list();
        if(files != null && files.length > 0) {
            byte[] bytes = FileUtils.getZipBytes(file, files);
            sendFile(new String(bytes), fileName, extension, type, response);
        }
    }
}

The "FileUtils.getZipBytes(file, files)" function is doing fine , it returns a byteArray. I even tried to create a zip file with ZipOutputStream a File , and on the server , the zip has litterally no problem. ( I will send the source code of this function if you think it's important , but i don't want to add useless complexity ).

Then , here's the code of the second sendFile function that is called from the first one.

public default void sendFile(String content, String fileName, FileExtension extension, ContentType type, HttpServletResponse response) {
    response.setContentType(type.getExpression());
    response.setHeader("Content-Disposition", "attachment; filename=\"" + FileUtils.encodeForFileName(fileName) + "." + extension.getExtension() + "\"");
    OutputStream out = response.getOutputStream();
    out.write(content.getBytes());
    out.flush();
    out.close();
}

Do you see any problem in these functions ?

The zip file is downloaded from the server. He is not empty (about 15.7KB). But when i try to open it , the file explorer of Fedora tell me that the file is corrupted.

I also tried to use the unzip command on the file , and i have the following error message.

Archive:  s192-Système U carquefou-2023-01-26 000000-2023-01-26 235959(1).zip

caution:  zipfile comment truncated
error [s192-Système U carquefou-2023-01-26 000000-2023-01-26 235959(1).zip]:  missing 3249308257 bytes in zipfile
  (attempting to process anyway)
error [s192-Système U carquefou-2023-01-26 000000-2023-01-26 235959(1).zip]:  attempt to seek before beginning of zipfile
  (please check that you have transferred or created the zipfile in the
  appropriate BINARY mode and that you have compiled UnZip properly)

I thought it may be the FileUtils.getZipBytes(file, files) that returns a corrupted ByteArray. But i really don't think it is ... Here's the source code of this function

    public static byte[] getZipBytes(File directory, String[] files) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ZipOutputStream zos = new ZipOutputStream(baos);
        byte bytes[] = new byte[2048];
        for (String fileName : files) {
            FileInputStream fis = new FileInputStream(directory.getPath() + 
                    System.getProperty("file.separator") + fileName);
            BufferedInputStream bis = new BufferedInputStream(fis);
            zos.putNextEntry(new ZipEntry(fileName));
            int bytesRead;
            while ((bytesRead = bis.read(bytes)) != -1) {
                zos.write(bytes, 0, bytesRead);
            }
            zos.closeEntry();
            bis.close();
            fis.close();
        }
        zos.flush();
        baos.flush();
        zos.close();
        baos.close();
        return baos.toByteArray();
}

Upvotes: 1

Views: 361

Answers (1)

Thomas Kläger
Thomas Kläger

Reputation: 21640

A zip file is not a string. You should drop the round trip from byte array to string and back to byte array.

Declare your sendFile() method as

public default void sendFile(byte[] content, String fileName, FileExtension extension, ContentType type, HttpServletResponse response) {
    response.setContentType(type.getExpression());
    response.setHeader("Content-Disposition", "attachment; filename=\"" + FileUtils.encodeForFileName(fileName) + "." + extension.getExtension() + "\"");
    OutputStream out = response.getOutputStream();
    out.write(content);
    out.flush();
    out.close();
}

And call it as

sendFile(bytes, fileName, extension, type, response);

The problem with your approach is that new String(content).getBytes() does not return a byte array with the same content as you started with.

Upvotes: 2

Related Questions