I can successfully download a ZIP-ped file when using returning the response as application/octet-stream
, but not when using multipart/form-data
. The downloaded ZIP has for each file inside the ZIP exactly 2 bytes that are wrong in the corresponding file headers.
Example binary output of the ZIP files:
- Correct ZIP content when using
application/octet-stream
:
PK�~�Xfirst_file.xml��,V�D���܂�Tg'��ĒDC=PK�T�CPK�~�Xsecond_file.xml��,V�D���܂�Tg'��ĒD#=PK�hPK�~�Xthird_file.xml��,V�D���܂�Tg'��ĒDc=PKW6�qPK�~�X�T�Cfirst_file.xmlPK�~�X�hYsecond_file.xmlPK�~�XW6�q�third_file.xmlPK�
- Broken ZIP content when using
multipart/form-data
:
PK��Xfirst_file.xml��,V�D���܂�Tg'��ĒDC=PK�T�CPK��Xsecond_file.xml��,V�D���܂�Tg'��ĒD#=PK�hPK��Xthird_file.xml��,V�D���܂�Tg'��ĒDc=PKW6�qPK��X�T�Cfirst_file.xmlPK��X�hYsecond_file.xmlPK��XW6�q�third_file.xmlPK�
Header Differences:
The initial header bytes for each of the three files inside the ZIP are PK��
, which are ZIP file signatures and headers. The bytes that differ (�~
vs �
) are part of the local files’ headers in the ZIP specification, specifically bytes representing information like modification time, CRC-32, compressed size, and uncompressed size. Since these bytes are corrupted, the ZIP tool does not recognize the files properly.
The minimal code to recreate the broken version:
try {
ResultSet rs = ...; // Here we properly set `rs`.
MultipartFormDataOutput multipartOutput = new MultipartFormDataOutput();
ByteArrayOutputStream zipByteOutputStream = new ByteArrayOutputStream();
zipOutputStream = new ZipOutputStream(zipByteOutputStream);
while (rs.next()) {
Clob fileClob = rs.getClob("fileContent");
ByteArrayOutputStream fileByteOutputStream = new ByteArrayOutputStream();
// ... Here we properly fill `fileByteOutputStream`.
ZipEntry entry = new ZipEntry("file.txt");
zipOutputStream.putNextEntry(entry);
zipOutputStream.write(fileByteOutputStream.toByteArray());
zipOutputStream.closeEntry();
}
zipOutputStream.close();
zipByteOutputStream.flush();
InputStream zipInputStream =
new ByteArrayInputStream(zipByteOutputStream.toByteArray());
multipartOutput.addFormData(
"file", zipInputStream, MediaType.valueOf("application/zip"), "zippedFiles.zip");
return Response.ok(multipartOutput).build();
} catch (IOException e) {
e.printStackTrace();
return Response.serverError().build();
} finally {
if (zipOutputStream != null) {
try {
zipOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}