Weird Issue with IE File Download - java

We've written a file download service.
On the client side, the download is attempted by Javascript. We create a dynamic form and a dynamic iframe and set the forms target to be the iframe.
On the Server Side we have the Content-Disposition header set.
This works in FF/Chrome and > IE9. For IE8 However, I see the download executes properly, the prompt comes up on IE8, but the file never downloads.
This is how it actually looks.
And this continues on forever. It never ends.
No File Save As prompt shows up.
I have tried changing the Content-Disposition Headers, experimented with flushing/closing response objects, changing content types...
Code on the server side is in the following form
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.addHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
//Calls some export function that returns an outputstream.
exportStream = export();
OutputStream responseStream = response.getOutputStream();
responseStream.write(exportStream.toByteArray());
responseStream.flush();
responseStream.close();
exportStream.flush();
exportStream.close();
I have no idea why this is happening and it is killing me now x-(

Related

Servlet error: Cannot call sendRedirect() after the response has been committed

I want to redirect to a page after writing the excel file. The servlet code is given below:
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
workbook.write(outByteStream);
byte [] outArray = outByteStream.toByteArray();
response.setContentType("application/ms-excel");
response.setContentLength(outArray.length);
response.setHeader("Content-Disposition", "attachment; filename=name_"+date+".xlsx");
response.setIntHeader("Refresh", 1);
OutputStream outStream = response.getOutputStream();
outStream.write(outArray);
response.sendRedirect("url/reports.jsp");
This code downloads an Excel file which i have created.
when i call the above servlet, the excel file is being downloaded but it is throwing following exception in the last line :
Servlet Error: ::java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
Hence i am unable to redirect to a new page. what can i do to access the response object after i write the output in "outStream"
The basic problem is that this ...
I want to redirect to a page after writing the excel file.
... describes two separate responses. The server cannot chain them together by itself because the client will expect only one response to each request. Because two requests are required to elicit two responses, automation of this sequence will require client-side scripting.
Personally, I would probably put the script on the front end: a handler on the appropriate button or link that first downloads the file and then (on success) issues a request for the new page. It would also be possible to do as suggested in comments, however: put script in the new page that downloads the file.
You cannot have a body with a redirect because the browser, when receiving a redirect, will issue a second request to the URL it has found (in header Location), and it's the response of that second request that is displayed, unless it is also a redirect, in which case, it will issue a third request, and so on...

After form-submit, download file

Im using struts2 and also servlets. (Due to a 3rd party ajax thing that ships with servlets).
One of my forms is posting to a servlet. (Name "/exclude/new.srl")
I've set struts2 up to ignore all requests to the "exclude" namespace.
So the request is reaching the servlet just fine.
The servlet does its job, and then goes on to do the following before ending:
response.getOutputStream().print("'OK'");
response.getOutputStream().close();
Now i dont know the 3rd party software in detail, so im not exactly sure, but i think the OK statement tells my 3rd party ajax-solution to close the form and refresh some contents of the page.
This all works fine.
Now however i am trying to add a new bit to this. I would like send a file to the user. In other words, when the form is submitted, everything that used to happen should still happen, but also the user should be asked to save or open a file.
So I have created a struts2 action that will return the file, no problem.
But how can i program the servlet to push this file to the user AND ALSO return response OK?
I do not need to use the struts2 action to push the file, if it can be done from within the servlet that is perfectly acceptable.
Anyone?
You can send the file
// Set the headers.
res.setContentType("application/x-download");
res.setHeader("Content-Disposition", "attachment; filename=" + filename);
// Send the file.
OutputStream out = res.getOutputStream();
File file = new File(yourPath);
response.setContentLength((int) file.length());
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
int readBytes = 0;
while ((readBytes = buf.read()) != -1)
stream.write(readBytes);
buf.close();
stream.close();
But how can i program the servlet to push this file to the user AND ALSO return response OK?
This I don't think is possible. The response from a servlet has a tyle, denoted by the content-type. If you set it to a download, then you cannot send a normal response, meaning you cannot send the "OK".
You will probably have to setup your unmentioned 3rd party ajax-solution to forward to the file action/servlet URL on form submission success (ie redirect to file download after form was submitted ok).

Problem occured when using OutputStream & (DataOutPutStream or PrintWriter)

I wrote a simple server using java socket programming and intended to make that offered 2 files for download and display some html response when the download finished. What I did is use PrintWriter.print or DataOutPutStream.writeBytes to send the string including html tags and response string to the browser, then use OutputStream.write to send the file requested. The URL I typed in the browser was like 127.0.0.1/test1.zip, relevant code fragments as following:
pout.print("<html>");
pout.print("<head>");
pout.print("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1/\">");
pout.print("<title>Response</title>");
pout.print("</head>");
pout.print("<body>");
pout.print(createResponseHeader(200, fileTypeCode));
pout.print("</body>");
pout.print("</html>");
pout.print(createResponseHeader(200, fileTypeCode));
pout.flush();
byte[] buffer = new byte[client.getSendBufferSize()];
int bytesRead = 0;
System.out.println("Sending...");
while((bytesRead = requestedFile.read(buffer))>-1)
{
out.write(buffer,0,bytesRead);
}
The pout is a PrintWriter while out is OutputStream.
The problem is when I try to use 127.0.0.1/test2.zip to download the file, it doesn't let me download, instead, print out the response string and a lot of non-sense character in the browser, e.g.
HTTP/1.0 200 OK
Connection: close
Server: COMP5116 Assignment Server v0
Content-Type: application/x-zip-compressed
PK‹â:Lmá^ЛàÍ test2.wmvì[y<”Ûÿ?3ÃØ—Ab¸eeË’5K"»±f_B*à Å*YÛ•¥M5h±¯u[(\·(-÷F)ß3ÏɽݺÝ×ýýñ{Íg^ÏûyžóYÏçœçyÎç¼P’>™îÝ+½Žö6A€;;ýmüH»êt©k]R#*€.G‰µÅRÏøÍLÔóZ; ´£åÑvP¹æª#õó”æÇ„‹&‡ëî9q‰Ú>LkÇÈyÖ2qãÌÆ(ãDŸã©ïÍš]Ð4iIJ0Àª3]B€ðÀ¸CôÁ`ä è1ü½¤Ã¬$ pBi
I believe it simply display the zip file as string with the response header all together. It seems once the PrintWriter is used before the code of sending the file, the whole output stream is used for sending string instead of bytes. However, if I put the part of code of sending the response AFTER the code of sending file, the download works properly but no any response message print out in the browser, just a blank page.
You've to remove your HTML code from here and send only the binary data. You can't mix them in a single servlet.
To achieve what you want to do is not easy.
I would start the download with some JavaScript code in the page, then the page will poll with Ajax for a server side servlet that will know if the download is completed for that particular session. In fact there is no download completed event in JavaScript.
To have this information the download servlet will update the session with a flag when download is completed.
When your Ajax call will return that the download is completed, you can change the text in the page or redirect to a new page.
Edit: Alternatively, if you can change your requirements, it will be much easier to show all messages that you have to show just before the download, and put target="_blank" in the download link so your page is not lost by clicking on the link.

How to send a PDF to the browser from a Java webapplication?

I have a java class that generates a PDF file to a folder in my computer. I have managed to connect this class to a link on a web application and when i click this link it generates the pdf and writes it to the folder on my computer. I would want to change this and have the link send the pdf to the browser instead. How can i do this? The class does not use any HttpRequests or similar and the link isnt a hypertext link atm. Im looking for the most straight forward way to send a pdf to the browser.
/* Java Code */
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=path/to/file.pdf");
i print it (any kind of file) to the response stream from a byte array, inside a servlet
if(content != null)
{
response.setContentType( "application/octet-stream" );
response.setHeader("Content-Disposition", "attachment; filename=\"" + fname + "\"");
response.setContentLength(content.length);
out.write(content);
}//where content is byte[]
You should be able to write the pdf to a stream, you can pass it the output stream from your response.
There are several ways to do that:
Put PDF file on some place available from Web, and then redirect user to URL, which will lead him to PDF file (if your web server supports this). Redirection may be easily done with "Location" HTTP header.
Send PDF file in HTTP response stream. Note, that you will have to set corresponding Mime-type in HTTP header. Implementation depends on web server / web framework you are using in your application.

Java webapp: adding a content-disposition header to force browsers "save as" behavior

Even though it's not part of HTTP 1.1/RFC2616 webapps that wish to force a resource to be downloaded (rather than displayed) in a browser can use the Content-Disposition header like this:
Content-Disposition: attachment; filename=FILENAME
Even tough it's only defined in RFC2183 and not part of HTTP 1.1 it works in most web browsers as wanted.
So from the client side, everything is good enough.
However on the server-side, in my case, I've got a Java webapp and I don't know how I'm supposed to set that header, especially in the following case...
I'll have a file (say called "bigfile") hosted on an Amazon S3 instance (my S3 bucket shall be accessible using a partial address like: files.mycompany.com/) so users will be able to access this file at files.mycompany.com/bigfile.
Now is there a way to craft a servlet (or a .jsp) so that the Content-Disposition header is always added when the user wants to download that file?
What would the code look like and what are the gotchas, if any?
I got this working as Pointy pointed out. Instead of linking directly to the asset - in my case pdfs - one now links to a JSP called download.jsp which takes and parses GET parameters and then serves out the pdf as a download.
Download here
Here's the jsp code I used. Its working in IE8, Chrome and Firefox:
<%#page session="false"
contentType="text/html; charset=utf-8"
import="java.io.IOException,
java.io.InputStream,
java.io.OutputStream,
javax.servlet.ServletContext,
javax.servlet.http.HttpServlet,
javax.servlet.http.HttpServletRequest,
javax.servlet.http.HttpServletResponse,
java.io.File,
java.io.FileInputStream"
%>
<%
//Set the headers.
response.setContentType("application/x-download");
response.setHeader("Content-Disposition", "attachment; filename=downloaded.pdf");
[pull the file path from the request parameters]
File file = new File("[pdf path pulled from the requests parameters]");
FileInputStream fileIn = new FileInputStream(file);
ServletOutputStream outstream = response.getOutputStream();
byte[] outputByte = new byte[40096];
while(fileIn.read(outputByte, 0, 40096) != -1)
{
outstream.write(outputByte, 0, 40096);
}
fileIn.close();
outstream.flush();
outstream.close();
%>
You wouldn't have a URL that was a direct reference to the file. Instead, you'd have a URL that leads to your servlet code (or to some sort of action code in your server-side framework). That, in turn, would have to access the file contents and shovel them out to the client, after setting up the header. (You'd also want to remember to deal with cache control headers, as appropriate.)
The HttpServletResponse class has APIs that'll let you set all the headers you want. You have to make sure that you set up the headers before you start dumping out the file contents, because the headers literally have to come first in the stream being sent out to the browser.
This is not that much different from a situation where you might have a servlet that would generate a download on-the-fly.
edit I'll leave that stuff above here for posterity's sake, but I'll note that there is (or might be) some way to hand over some HTTP headers to S3 when you store a file, such that Amazon will spit those back out when the file is served out. I'm not exactly sure how you'd do that, and I'm not sure that "Content-disposition" is a header that you can set up that way, but I'll keep looking.
Put a .htaccess file in the root folder with the following line:
Header set Content-Disposition attachment
I just found this via google.
And I had a simmilar problem, but I still want to use a Servlet (as I generate the Content).
However the following line is all you need in a Servlet.
response.setHeader("Content-Disposition", "attachment; filename=downloadedData.json");

Categories

Resources