Can't open zip archive after upgrading to Spring boot 1.5.1 - spring-boot

I switched from spring boot 1.4.3.RELEASE to 1.5.1.RELEASE. I have an HttpServletResponse to which I write the content of the archive, which is downloadable via a rest-endpoint. The file gets downloaded, but I can't open it anymore with the zip unarchiver, which is not the case when using spring boot 1.4.3.
The response headers look like this
X-Frame-Options:DENY
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
X-Content-Type-Options:nosniff
Content-Disposition:attachment; filename="myfile.zip"
Connection:close
Pragma:no-cache
Expires:0
Content-Transfer-Encoding:binary
X-XSS-Protection:1; mode=block
Content-Length:1054691
Date:Tue, 28 Feb 2017 05:39:32 GMT
Content-Type:application/zip
Those are the methods responsible with writing the file to the response:
public void writeZipToResponse(HttpServletResponse response) throws IOException {
Optional<MyObject> myObject= findMyObject();
if (myObject.isPresent()) {
response.addHeader("Content-type", AdditionalMediaTypes.APPLICATION_ZIP);
response.addHeader("Content-Transfer-Encoding", "binary");
response.addHeader("Content-Disposition", "attachment; filename=\"" + myObject.get().getName() + ".zip\"");
response.setStatus(HttpStatus.OK.value());
int lengthOfFile = writeObjectAsArchive(myObject.get(), response.getOutputStream());
response.addHeader("Content-Length", String.valueOf(lengthOfFile));
}
else {
response.setStatus(HttpStatus.NOT_FOUND.value());
}
}
and this:
int writeObjectAsArchive(Collection<Dummy> dummies, OutputStream out) {
try {
ZipOutputStream zipArchive = new ZipOutputStream(out);
int length = 0;
for (Dummy dummy: dummies) {
ZipEntry entry = new ZipEntry(dummy.getFileName());
zipArchive.putNextEntry(entry);
byte[] fileAsByteArray = dummy.getFileAsByteArray();
zipArchive.write(fileAsByteArray);
zipArchive.closeEntry();
length += fileAsByteArray.length;
}
zipArchive.finish();
return length;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}

You must close the output stream.
int writeObjectAsArchive(Collection<Dummy> dummies, OutputStream out) {
try {
ZipOutputStream zipArchive = new ZipOutputStream(out);
...
zipArchive.finish();
zipArchive.close();
return length;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}

Related

Download rtf file spring boot

Good afternoon.
I need to download an rtf file that was put into the database as a byte[] to the user. The application runs on the server, and it coulnd be unloaded on the client's PC. I took methods from my previous project. There it was necessary to form and unload the exel file. I tried to upgrade them for this task, but I ran into one problem.
Naturally, I can't get the MediaType for byte[].
Tell me, can I somehow explicitly specify it?
public class MediaTypeUtils {
public static MediaType getMediaTypeForFileName(ServletContext servletContext, String fileName) {
String mineType = servletContext.getMimeType(fileName);
try {
MediaType mediaType = MediaType.parseMediaType(mineType);
return mediaType;
} catch (Exception e) {
return MediaType.APPLICATION_OCTET_STREAM;
}
} }
public static ResponseEntity<InputStreamResource> downloadFile1(ServletContext servletContext, PaymentOrderArchive archive) throws IOException {
MediaType mediaType = MediaTypeUtils.getMediaTypeForFileName(servletContext, archive.getRtffilename());
InputStream resource = null;
try (FileOutputStream stream = new FileOutputStream(archive.getRtffilename())) {
stream.write(archive.getEfile());
IOUtils.copyLarge(resource, stream);
InputStreamResource file = new InputStreamResource(resource);
return ResponseEntity.ok()
// Content-Disposition
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + archive.getRtffilename())
// Content-Type HERE
.contentType(mediaType)
// Contet-Length
.contentLength(resource.available()) //
.body(new InputStreamResource(resource));
}
}

Spring boot RestTemplate upload file to SharePoint online but file is corrupted

There is a RestController and I try to upload a MultiPartFile to SharePointOnline using, the SharePoint REST API I'm also using proxy due to corporate restrictions.
#Override
public ResponseEntity uploadFile(MultipartFile file) throws ApiException, IOException {
RestTemplate restTemplate = createBasicRestTemplate();
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file",file.getResource());
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> uploadBodyEntity = new HttpEntity<>(body, header);
ResponseEntity<String> response = restTemplate.exchange(BASE_URL, HttpMethod.POST,
uploadBodyEntity, String.class);
return response;
}
public RestTemplate createBasicRestTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder(new ProxyCustomizer()).build();
return restTemplate;
}
#Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
#Override
public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
return super.determineProxy(target, request, context);
}
})
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
The file upload is success, but it's cannot be opened. For example if upload a txt it will looks like this:
--raF_ORlUJptia2_av7ppLBeeMcGf5BUr
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Content-Length: 159
--38dc5323d6b92b5c14c33fade0178306
Content-Disposition: form-data; name="file"; filename="test.txt"
blablalblalalal
--38dc5323d6b92b5c14c33fade0178306--
--raF_ORlUJptia2_av7ppLBeeMcGf5BUr--
If I upload an xlsx it's simply just not open, it shows 'File Format and Extension Don't Match' error.
I try to convert the MultiPartFile to simple File with this method:
public File convertFile(MultipartFile file) {
File convFile = new File(file.getOriginalFilename());
try {
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return convFile;
}
and change the controller to:
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file",convertFile(file));
But the same thing happens.
How can I upload file with RestTemplate?
This is a sample request to the SharePoint REST API and based on documentation the endpoint should receive a array buffer
POST https://{site_url}/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files/add(url='a.txt',overwrite=true)
Authorization: "Bearer " + accessToken
Content-Length: {length of request body as integer}
X-RequestDigest: "{form_digest_value}"
"Contents of file"
This is what i can see in the https log: http log
Solution was to remove MultiValueMap and replace with:
HttpEntity<byte[]> entity = new HttpEntity<>(file.getBytes(), spoHelperService.createAuthHeader(authToken));
ResponseEntity<SpoUploadResponse> response = restTemplate.exchange(uploadFileUrl, HttpMethod.POST,
entity, SpoUploadResponse.class);

Spring mvc upload multiple files at once with AJAX doesn't work

I'm using Spring boot 2.0.1 and I'm trying to upload multiple files with dropzone. Everything is working perfectly when I'm using uploadMultiple: false on Dropzone.js. When I set uploadMultiple: true, My Controller stops working.
The controller class is as follow:
#PostMapping(value = "/img/upload")
public ResponseEntity<?> fileUpload(#RequestParam("file") MultipartFile[] files){
System.out.println(files.length);
for (MultipartFile file : files) {
try {
file.transferTo(new File("/opt/img/" + file.getOriginalFilename()));
System.out.println(file.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
}
return new ResponseEntity<>("File Uploaded Successfully.", HttpStatus.OK);
}
The files are no more than 1MB and my settings are
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
My request header when I upload the files:
------WebKitFormBoundaryihPcX9WHR5UA9jGD
Content-Disposition: form-data; name="file[0]"; filename="cars-02-01.png"
Content-Type: image/png
------WebKitFormBoundaryihPcX9WHR5UA9jGD
Content-Disposition: form-data; name="file[1]"; filename="Screenshot from 2018-05-03 23-31-53.jpg"
Content-Type: image/jpeg
Everything seems perfect. I still cannot find the reason for this problem?
It seems that I should use the MultipartHttpServletRequest instead of MultipartFile[] files. I Changed the method to:
#PostMapping(value = "/img/upload")
public ResponseEntity<?> fileUpload(MultipartHttpServletRequest request) {
Map<String, MultipartFile> fileMap = request.getFileMap();
for (MultipartFile file : fileMap.values()) {
try {
file.transferTo(new File("/opt/img/" + file.getOriginalFilename()));
System.out.println(file.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
}
return new ResponseEntity<>("File Uploaded Successfully.", HttpStatus.OK);
}

Java Exception getOutputStream() has already been called for this response while downloading file from backend

I have this code in order to download files from backend:
final File file = new File(filePath);
String fileType = Files.probeContentType(file.toPath());
response.setContentType(fileType);
response.setHeader("Content-disposition: attachment;", "filename=\"" + fileName + "\"");
response.setContentLength((int)new File(filePath).length());
final OutputStream os = response.getOutputStream();
IOUtils.copy(is, os);
response.flushBuffer();
os.flush();
os.close();
is.close();
and I get this exception in backend:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:578)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212)
Does anyone know what I can do in order to prevent this exception?
As far as I know you shouldn't call flush and/or close on the response outputstream
Other way would be to delegate all to Spring controller
I always use this code and I never had problems
#RequestMapping(method = { RequestMethod.GET },
value = { "/file/{idFile}" })
public ResponseEntity<InputStreamResource> downloadCsv(
#PathVariable("idFile") String idFile) {
try {
File file = new File("yourFilePath");
HttpHeaders respHeaders = new HttpHeaders();
//Add your mediaType....mine was csv
MediaType mediaType = new MediaType("text","csv");
respHeaders.setContentType(mediaType);
respHeaders.setContentLength(file.length());
respHeaders.setContentDispositionFormData("attachment", file.getName());
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
} catch (Exception e) {
String message = "Errore nel download del file "
+ idFile + ".csv; "
+ e.getMessage();
logger.error(message, e);
return new ResponseEntity<InputStreamResource>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I hope this can be useful
Angelo

IE image not getting loaded with X-Content-Type-Options:nosniff

Intro
I have spring MVC application I'm loading image from controller. For security purpose, I added X-Content-Type-Options:nosniff to my Spring application
By setting the following in springConfig xml <security:content-type-options/>
Problem : after this IE is not loading the images responded by controller. I suspect the content type is not set in the response. Because another site which is responding X-Content-Type-Options:nosniff and Content-Type:image/png; is working fine.
TRY1
I tried to change my controller to set content type. But it is not happening.
#RequestMapping(value = "/getUserImage" , produces = org.springframework.http.MediaType.IMAGE_PNG_VALUE)
public #ResponseBody
void getUserImage(
#RequestParam(value = "userId", required = false) int userId,
HttpServletRequest request, HttpServletResponse response) {
try {
//Get file and add it to response
IOUtils.copy(inputStream, response.getOutputStream());
response.getOutputStream().flush();
response.setContentType(org.springframework.http.MediaType.IMAGE_PNG_VALUE);
response.setHeader("Content-Type","image/png");
response.flushBuffer();
inputStream.close();
} catch (Exception e){
}
}
TRY2
I tried to add response header as the same way in method interceptor but still no luck.
But the same thing working in Chrome and Firefox.
Try this :
#RequestMapping(value = "/image/{personId}")
#ResponseBody
public HttpEntity<byte[]> getPhoto(#PathVariable int personId) {
Person person = this.personService.getPersonById(personId);
if (person != null && person.getProfileThumbnail() != null) {
try {
byte[] image;
try {
image = org.apache.commons.io.FileUtils.readFileToByteArray(new File(msg + "/" + person.getUsername() + "/" + personId + ".png"));
} catch (FileNotFoundException e) {
image = org.apache.commons.io.FileUtils.readFileToByteArray(new File(defaultProfilePath));
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(image.length);
return new HttpEntity<>(image, headers);
} catch (IOException ignored) {
}
}
}
What I am basically doing is checking if there is an image on File-system for the user, if not then I am loading a default image. Right now it works on all browser, so even if personid is 0, I get default image back, with the else cause, which I have not posted here.

Resources