File can not be copied to response steam - java

There is an interesting error on a page. I wonder if you have any idea about it.
In order to download a file, we write the file to responseStream but if file is less than 8,3KB, we get file not found error although file is there.
If i increase the file size (using some dummy values), it works
I suspect it has something to do with the contentLength of response but it seems fine to me
file = new File(ef.getPath());
response.setContentLength((int) file.length());
fileIs = new FileInputStream(file);
FileCopyUtils.copy(fileIs, response.getOutputStream());
Please help me if you have any idea?

How try with adding Content-Disposition header and setContentType()
response.setHeader("Content-Disposition", "attachment; filename=\""+ fileName + "\"");
String mimeType = new MimetypesFileTypeMap().getContentType(fileName);
response.setContentType(mimetype);

Related

How to set content length for file downloaded using URL class, using Java/Spring MVC?

Following is Java code used to download file in Spring MVC Ajax call.
I need to set Content Length which I am unable to find using URL.openStream().
URL fileToDownload = new URL(form.getDownloadLink());
InputStream fileContents = fileToDownload.openStream();
response.setContentType("application/docx");
response.setHeader("Content-Disposition", "attachment; filename="+fileName+"");
response.setContentLength(<Length>);
ServletOutputStream outputFile = response.getOutputStream();
IOUtils.copy(fileContents, outputFile);
response.flushBuffer();
fileContents.close();
outputFile.close();
Could anyone guide how to get length of Stream?
We download PDF and DOCX files of different sizes using above

open pdf file with sessionAsSigner

I have a database where the user doesn't has access to.
Still I can go to the database and "read" the documents with for example
var db:NotesDatabase = sessionAsSigner.getDatabase("","somedir/some.nsf");
In this database there's a pdf file I would like to open or download. I have the filename and the unid . If the user had acces to the database I could do it with
http(s)://[yourserver]/[application.nsf] /xsp/.ibmmodres/domino/OpenAttachment/ [application.nsf]/[UNID|/$File/[AttachmentName]?Open
How can I do it with sessionAsSigner without putting a $PublicAccess=1 field on the form ?
edit:
the pdf file is stored as attachment in a richtextfield
second edit
I'm trying to use the XSnippet from Naveen and made some changes
The error message I get is : 'OutStream' not found
The code I tried is :
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=" + zipFileName);
var embeddedObj:NotesEmbeddedObject = null;
var bufferInStream:java.io.BufferedInputStream = null;
var outStream:java.io.OutputStream = response.getOutputStream();
embeddedObj = downloadDocument.getAttachment(fileName);
if (embeddedObj != null) {
bufferInStream = new java.io.BufferedInputStream(embeddedObj.getInputStream());
var bufferLength = bufferInStream.available();
var data = new byte[bufferLength];
bufferInStream.read(data, 0, bufferLength); // Read the attachment data
ON THE NEXT LINE IS THE PROBLEM
OutStream.write(data); // Write attachment into pdf
bufferInStream.close();
embeddedObj.recycle();
}
downloadDocument.recycle();
outStream.flush();
outStream.close();
facesContext.responseComplete();
Create an XAgent (= XPage without rendering) which takes datebase + documentid + filename as URL parameters and delivers the file as response OutputStream.
The URL would be
http(s)://[yourserver]/download.nsf/download.xsp?db=[application.nsf]&unid=[UNID]&attname=[AttachmentName]
for an XAgent download.xsp in a database download.nsf.
The code behind the XAgent runs as sessionAsSigner and is able to read the file even the user itself has no right to access file's database.
Use Eric's blog (+ Java code) as a starting point. Replace "application/json" with "application/pdf" and stream pdf file instead of json data.
As an alternative you can adapt this XSnippet code from Thomas Adrian. Use download() together with grabFile() to write your pdf-File to OutputStream.
Instead of extracting attachment file to path and reading it from there you can stream the attachment right from document to response's OutputStream. Here is an XSnippet from Naveen Maurya as a good example.
If you can get the PDF file as a stream, you should be able to use the OutputStream of the external context's response.
Stephan Wissel has a blog posting about writing out an ODF file so you should be able to cut that up as a starting point.
http://www.wissel.net/blog/d6plinks/SHWL-8248MT
You already have the db so, you will just need to know the UNID of the document.
var doc = db.getDocumentByUNID(unid) 'unid is a supplied param
var itm:RichTextItem = doc.getFirstItem("Body") 'assuming file is in body field
Once you have the itm, you can loop round all of the embeddedObjects and get the pdf file. At this point, I don't know if you can stream it directly or if you have to detach it, but assuming you detach it, you will then use something like this.
File file = new File("path to file");
FileInputStream fileIn = new FileInputStream(file);
Don't forget to clean up the temporarily detached file

Java file download isn't downloading an exact copy of the file

I have a Java servlet that implements a file download. It includes the following code:
String filename = request.getParameter("filename");
File file = new File(filename);
FileInputStream inputStream = null;
ServletOutputStream outputStream = response.getOutputStream();
ServletContext servletContext = getServletContext();
String mimeType = servletContext.getMimeType(filename);
if (mimeType == null)
mimeType = "application/octet-stream";
logger.trace("MIME type for " + filename + " is " + mimeType);
response.setContentType(mimeType);
response.setContentLength((int)file.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
inputStream = new FileInputStream(file);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
if (inputStream != null)
inputStream.close();
On the server we have a file.tar.gz, and when the browser sends the request to download that file, I see a line in the log file saying that the "MIME type for file.tar.gz is application/x-gzip". But when we compare the file that the browser saved to the file on the server, they are not the same.
Then I commented out the "if (mimeType == null)" line so that the MIME type would always be set to "application/octet-stream", and the downloaded file still wasn't identical to the one on the server.
Any idea why the downloaded file isn't exactly the same as the file on the server?
EDIT: This is really strange. I tested a text file, a PDF file, a ZIP file (created in Windows), a JPG file, and they all download exact copies. Just this file.tar.gz doesn't get downloaded exactly for some reason (on the server it's 882,273 bytes, and the downloaded copy is 881,968 bytes).
EDIT 2: When I use curl to download the file.tar.gz, it gets saved as an exact copy, so that tells me there's nothing wrong with the servlet code. Chrome is modifying the file before it saves it for some reason. Could Chrome be detecting that the file is a gzipped file and thinks that the server compressed the response (when it really didn't), so it tries to uncompress it? Then again the file that Chrome saves is smaller than the file on the server...
This problem occurred due to a bug in Chrome, as described here:
https://code.google.com/p/chromium/issues/detail?id=268085
Our web server was configured to use HTTP gzip compression for everything sent back to the browser, so due to the Chrome bug, it ended up saving the file with another layer of gzip compression.

Downloading file stops just before finish - caused by Content Length in response header

The following code is used to prepare a file to be downloaded:
File downloadFile = new File(ftpPath + File.separator + company.toLowerCase() + File.separator + "download" + File.separator + paramFileName);
FileInputStream fis = new FileInputStream(downloadFile);
BufferedInputStream bis = new BufferedInputStream(fis);
response.setContentType("binary");
response.setHeader("Content-Disposition", "attachment; filename="+paramFileName);
response.setHeader("Content-Length",String.valueOf(downloadFile.length()));
response.setHeader("Content-Encoding", "utf-8");
ServletOutputStream sos = response.getOutputStream();
IOUtils.copy(bis, sos);
sos.flush();
fis.close();
bis.close();
sos.close();
When a file is clicked and downloaded, while the total file size is correctly visible in the download progress bar, the file never actually finishes downloading. For large files, it gets about 95%+ of the way there and then stops completely. For smaller files, the results are less consistent, but the file never finishes downloading in it's entirety.
If I remove the following lines, the file does completely download:
/*
response.setHeader("Content-Length",String.valueOf(downloadFile.length()));
response.setHeader("Content-Encoding", "utf-8");
*/
However, the total file size is not given when the file begins downloading. This is very inconvenient for our users, who may be downloading a large file and would like to know an approximate "time to completion" number.
Is there a fix which will allow the file to completely download and also give an accurate indication of the file size?
Thanks for the help
Note: Got rid of DataInputStream as it was never used.

Question regarding streams in java

We have the below requirement.
We will have to create an excel/pdf report and then download it on click of a button in a java web application. The pdf/excel file is dynamically created using application data.
We should not create any physical file on the server.
How do we go about this? Are there any streams through which I can read and write in the same go without having to close in between.
You could use memory-based streams (such as ByteArrayInputStream and ByteArrayOutputStream) and use the same underlying byte buffer to address the read/write in the same go part of the question.
As others have pointed out, you can just write directly to the output stream of the response.
Look at ServletResponse.getOutputStream().
You need to write to this stream from the one created by your report API. Don't forget to set the proper content-type using setContentType() method of the same class.
Here you can find how you can do it with jxl API and it may help you also.
How do I output an Excel file from a Servlet?
Whatever PDF or Excel API you are using to generate the files, you should lookup the constructor or method which takes an OutputStream to write the generated PDF/Excel content to. You should just feed it with response.getOutputStream() instead of FileOutputStream.
For example, iText for PDFs:
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
PdfWriter pdfWriter = PdfWriter.getInstance(document, response.getOutputStream());
// ...
And Apache POI for Excel:
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
WritableWorkbook workBook = Workbook.createWorkbook(response.getOutputStream());
// ...
Have a Servlet serve the pdf/excel file as a byte array.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] bytes = null; // get this from somewhere in your app
String fileName = "filename.pdf"; // whatever you wish to name the file
ServletOutputStream out = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setContentType("application/pdf");
response.setContentLength(bytes.length);
out.write(bytes);
out.flush();
}
MIME type for MS Excel files would be application/vnd.ms-excel.

Categories

Resources