I have a servlet that allows users to download (potentially large) zip files from a web page. If the user clicks on a link to download a zip file, code similar to the following is executed in the servlet:
response.setContentType("application/zip");
response.setHeader("Content-disposition", "attachment; filename=foo.zip");
response.setHeader("Pragma", "");
response.setHeader("Cache-Control", "no-store");
ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
// write entries to the zip file...
...
out.close()
However, if the user refreshes or navigates away from the page after the download begins and before it completes (in Firefox 3.5.7), the download will fail. The following error pops up:
C:\blah\foo.zip.part could not be
saved, because the source file could
not be read.
Try again later, or contact the server
administrator.
Any ideas on how I can make sure the download continues in this case?
UPDATE: The link that initiates the download is a plain vanilla link. Interestingly, the behavior is different on IE. Clicking on links elsewhere on the site (from the currently loaded screen) seem not to load (the browser status bar says "Waiting for https://mysite/clicked_linky.do..."), blocking until the download completes. Typing a different URL into the address bar or using a shortcut/favorite link navigates away from the page, but the download continues as expected. Only Firefox seems to display the exact behavior I described above, although the IE blocking is not optimal.
This should in fact not happen. The download counts as a separate request which is supposed to be run in the background independently from the parent page once invoked. How exactly are you firing the download request? By a plain vanilla link or a link which (incorrectly) fires an ajaxical request to run the download?
At any way, you at least clearly want to be able to resume downloads. In this case you need to send at least the Accept-Ranges, ETag and Last-Modified response headers along the download accordingly. The client can then ask to resume the download by sending the If-Range and Range request headers with respectively the file identifier and a specified byte range which you could use in combination with RandomAccessFile to send the remaining bytes. You can find more information and a servlet sample in this article.
That's the theory. In your particular case, it's a bit tricker as you're zipping the files on the fly. You'll need to write the zip into a temporary folder of the server's local disk file system first and then stream from it and finally delete the file only when the download is successfully completed (i.e. the out.close() didn't throw IOException). You can identify the associated zip file with help of request parameter or pathinfo or maybe a key in session.
Update: as per your update: I honestly don't know and I've never experienced it, but at least I can tell that you're not the only one who suffered from this problem. At least, implementing the resume capabilities as described before may be a solution to this particular problem as Firefox would then automatically resume the download without jerking about an incomplete part.
Update 2: after having a little thought after reading your update and the browser behaviours, it look like that there's a fairly huge time gap between firing the actual request and the arrival of the response headers. I don't know the exact details how you load the files, but it look like that there is a time cost in gathering the ZIP files (maybe you're loading them from a networked filesystem or database beforehand?) and that you set/send the response headers only after you have gathered all the ZIP files. Try setting the headers and doing the output.flush() before doing the expensive task. This way the browser will get the headers as soon as possible and it will know what it may expect.
I suspect it's an artefact of using servlets - probably as a result of reassigning the thread. Certainly I have no such problem with a similar setup written in PHP (where each request is handled by a (effectively) new process.
HTH
C.
Related
Is there a way to display a (preferably modal) dialog box in an servlet controller ? If it isn't modal that is something I can deal with (!?) as long as it initially appears above the browser.
Essentially I have a form with a table and 2 buttons on it. One button takes the user to a different place in the workflow and is irrelevant to this question (just to explain why the other one doesn't 'go anywhere').
The other button currently goes back to an MVC controller, calls some code to export the table to excel and then reloads the web page. This is all working okay except the way I am calling the dialog box is calling it underneath the browser. I suspect this is because I am sending null as the frame but I'm not sure what to put in its place ?
JOptionPane.showMessageDialog(null, "Export Completed.", "Excel Export", JOptionPane.INFORMATION_MESSAGE);
Many thanks.
I am not too sure what you are trying to achieve from your question and without any code examples. However, presumably what you are doing (guessing here), is that you are trying to export some data from some data source and convert it to an Excel file. You have to keep 3 things in mind.
Web applications work via HTTP requests and responses. So the only thing a Servlet can do is send back an HTTP response that indicates that the export was successful. Whether you use a traditional page, or maybe use AJAX to avoid refreshing the page is purely your design choice. You could also start with a simple page and then change to AJAX combined with JQuery later once you get used to what is happening.
Exporting the excel sheet to the server does not mean that your client has access to it. Speculating here, but you will probably need a mechanism for your user to get the file. One simple approach used by many webapps is to actually send the Excel file as the Servlet response itself. So what would happen is that when the export is completed the browser starts receiving the file and the user sees it downloading. From your servlet you will just need to set the right mime-type and set the content-disposition header to state that the file is an attachment (so that the browser downloads it as a file).
httpresp.setContentType("text/csv");
httpresp.setHeader("Content-disposition", "attachment; filename=\"export.csv\"");
You will probably also need to set the file size. There are various full examples on SO if you look for further details.
When performing these operations remember that users can interrupt the browser or refresh. If the user presses F5 he might cause your application to do the export again. One common approach to this is called 'redirect-after-post'. Basically you redirect the user to a page which just displays the outcome, without performing the operation again. This way if he presses refresh, he is just refreshing the page with the message.
It is quite a common question but I can't find an answer to it
I have a simple HTML with an input text box (type=file) and a submit button. On clicking the submit button, I call a js function where I try to get the complete path of the file
var data = $('#fileName').val();
the issue is I am not getting complete file path of the file I am uploading. I know due to security reasons chrome gives me a C:\fakePath\filename and firefox gives me only the fileName. But in case I need a complete path what shall I do?
PS: Further I will make an ajax call and give that file path to the back-end which needs it to read that file using FileReader
You cannot get the complete path! there is no way to do that!! Even though you are on an intranet and you have enough permissions.
A workaround for this is to have a textarea and ask the user to enter the complete path of the file.
In short you can't have the full name of a file once is loaded on server side, you will just have the file name and its content in a raw byte array (among other attributes). This is not a Java thing nor other server side technologies issue, is related to browser implementation (but it looks that IE6 may contain a flaw about this).
Not directly related to your question but caught my attention
PS: Further I will make an ajax call and give that file path to the back-end which needs it to read that file using FileReader
Usually, you can't handle a file upload using ajax because it can lead to security holes. Still, there are some browsers (like Chrome and Firefox) that allows you to send a file using XMLHttpRequest but that isn't allowed on some browsers (like IE8-) so you have to use an iframe in order to make the file ajax uploading work.
In order to avoid handling all these problems, I would advice you to use a third-party js library that handles the ajax file upload. An example is blueimp jQuery file upload that also has Java server side examples (DISCLAIMER: I do not work in this project nor I'm associated with blueimp in any way). Note that using this plugin requires that you have a mid knowledge on HTML/JavaScript/jQuery/Java Server Side so if you're a starter it may take you some time to make it work, but once it does is pretty good.
I dont know which technology you are using.. but you can always get file name once it is uploaded on server (Using php or .net )
your steps to upload should be like below:
1) Upload file to the server (e.z. /uploadedFiles/...filename
2) Create a method which will fetch file name from the uploaded path
3) simply insert file name in to the database (this will give you flexibility to change folder name of uploaded docs in future if required)
Generally filenames are not stored as it is . to avoid name conflict in future. So it is a advisable to always rename your filename by adding minutes & seconds after itsname.
If any doubts do ask.
Hope it helps.
Browsers block the filepath access on javascript for securit reasons.
The behavior makes sense, because the server doesn't have to know where the user stores the file on his computer, it is irrelevant to the upload process.
I am developing an application using struts2 framework. When user provides date range, I need to prepare the reports excel file and show that in download pop-up. I am able to create io stream of excel, but I am not getting how can I open that pop-up using ajax.
I am generating file on the fly and returns the stream. Therefore not able to give file path. I want ajax call to show some message like "Please wait..". Because file generation takes more time and it looks like link is not working..
There's nothing Ajax about downloading a file.
Your request can be an ajax request, but simply give the generated file path and the browser will do the downloading.
No need to perform any AJAX calls.
You just need to return the byte[] as a Struts2 Stream result,
configured with a ContentDisposition: attachment; (and not ContentDisposition: inline, that will try to open it inside the browser instead of asking about downloading or opening with a desktop application).
To notify the user that something is going on, that the request is sent and the system is not frozen, you need an Loading OVERLAY.
An Overlay is an element that is placed over your page, generally with a partially transparent background, an animated image saying "Loading..." , and a modal behavior (it won't close until the page is changed, and it will prevent double post of the same request, like double clicks etc...).
Of course if you open an attachment, the page will not change, then you'll need to intercept the end of the downloading and close the overlay by yourself, or give the user a button to close it.
To intercept it, you can try the Struts2 Execute and Wait Interceptor.
If you want to create a custom overlay, you can generate your Loading images with the ajaxload.info Generator.
If you instead don't want to reinvent the wheel, you can take a look at existing overlays, like those from jQuery TOOLS.
On the success method of ajax do not return the stream, instead save the file on server and open a pop up with address to an action that returns correct file. But pop ups might be blocked in some browsers so you need to allow that for your site (local host or other URL)
Requirement is to keep a copy of complete web page at server side same as it is rendered on client browser as past records.These records are revisited.
We are trying to store the html of rendered web page. The html is then rendered using resources like javascript, css and image present at server side. These resources keep on changing. Therefore old records are no longer rendered perfectly.
Is there any other way to solve above? We are also thinking converting it into pdf using IText or apache FOP api but they does not consider javascript effect on page while conversion. Is there any APIs available in java to achieve this?
Till now, no approach working perfectly. Please suggest.
Edit:
In summary,requirement is to create a exact copy of rendered web page at server side to store user activities on that page.
wkhtmltopdf should do this quite nicely for you. It will take a URL, and return a pdf.
code.google.com/p/wkhtmltopdf
Example:
wkhtmltopdf http://www.google.com google.pdf
Depending on just how sophisticated your javascript is, and depending on how faithfully you want to capture what the client saw, you may be undertaking an impossible task.
At a high level, you have the following options:
Keep a copy of everything you send to the client
Get the client to return back exactly whatever it has rendered
Build your system in such a way that you can actually fetch all historical versions of the constituent resources if/when you need to reproduce a browser's view.
You can do #1 using JSP filters etc, but it doesn't address issues like the javascript fetching dynamic html content during rendering on the client.
Getting the client to return what they are seeing (#2) is tricky, and bandwidth intensive.
So I would opt for #3. In order to turn a website that renders dynamic content versioned, you have to do several things. First, all datasources need to versioned too. So any queries would need to specify the version. "Version" can be a timestamp or some generation counter that you maintain. If you are taking this approach, you would also need to ensure that any javascript you feed to the client does not fetch external resources directly. Rather, it should ask for any resources from your system. Your system would in turn fetch the external content (or reuse from a cache).
The answer would depend on the server technology being used to write the HTML. Are you using Java/JSPs or Servlets or some sort of an HTTPResponse object to push the HTML/data to the browser?
If only the CSS/JS/HTML are changing, why don't you just take snapshots of your client-side codebase and store them as website versions?
If other data is involved (like XML/JSON) take a snapshot of those and version that as well. Then the snapshot of the client codebase as mentioned above with the contemporary snapshot of the data should together give you the exact rendering of your website as at that point of time.
A very resource-consuming requirement but...
You haven't written what application server you are using and what framework. If you're generating responces in your own code, you can just store it while generating.
Another possibility is to write a filter, that would wrap servlet's OutputStream and log everything that was written to it, you must just assure your filter is on the top of the hierarchy.
Another, very powerfull, easiest to manage and generic solution, however possibly the most resource-consuming: write transparent proxy server staying between user and application server, that would redirect each call to app server and return exact response, additionally saving each request and response.
If you're storing the html page, why not the references to the js, css, and images too?
I don't know what your implementation is now, but you should create a filesystem with all of the html pages and resources, and create references to the locations in a db. You should be backing up the resources in the filesystem every time you change them!
I use this implementation for an image archive. When a client passes us the url of an image we want to be able to go back and check out exactly what the image was at that time they sent it (since it's a url it can change at any time). I have a script that will download the image as soon as we receive the url, store it in the filesystem, and then store the path to the file in the db along with other various details. This is similar to what you need, just a couple more rows in your table for the js, css, images paths.
I have a download servlet which generates a ZIP with some files, one of them pretty big, and then sends the generated file in the response for download.
The problem is that the generating process is pretty big, and between the step of the generation of de ZIP and the download step (when the user see the download dialog) many seconds or even a minute could pass. So I would like to inform the user by anyway that the file is being generated.
The solution I'm thinking about is doing several requests, one for open a modal window which informs the user and inside this, then do another request automatically to an action which generates the file in a temp location and then, when the request ends, another one which closes the window (the window must be closed automatically) and then request to the download servlet the generated file in the last step.
If somebody understands what I'm trying to do, I would like if exists a better and cleaner solution.
You can fire an ajax request which will start the generation process, and then other ajax requests to poll the server if the file is ready. If yes - change the location of the browser to the file. Otherwise, show a "loading" message/image/..