Browser Event When Downloaded File Is Saved to Disk

Browser event when downloaded file is saved to disk

There's no such browser event in JavaScript and even if there was you can not trust the user's browser to provide security for you.

You're better off using a GUID to generate a unique URL for each download. You can then for example:

  • let the URL be valid only for a specific time period
  • allow transfers only from a specific IP address associated with the unique URL
  • let your server-side code detect when the content for a unique URL has been fully transferred and then invalidate the URL.

Let me clarify the last bullet. Say you're using Java - you will in.read(buffer) and out.write(buffer) in a loop until EOF. If the client disconnects you will receive an IOException during out.write() and will be able to tell a successful download from an interrupted one. On other platforms, I'm sure there are ways to tell whether the connection was lost or not.

EDIT: You could actually fire a browser event using the trick outlined in the accepted answer of one of the questions you linked to. That would however not be a reliable solution to limit the number of downloads.

Detect when user accepts to download a file

As i've found from years of maintaining download.js, there simply is no way to tell from JS (or likely in general, see below) what a user chooses to do with the download Open/Save dialog. It's a common feature request, and i've looked into it repeatedly over the years. I can say with confidence that it's impossible; I'll joyfully pay 10 times this bounty if someone can demo a mechanical way to determine the post-prompt user action on any file!

Further, it's not really just a matter of JS rules, the problem is complicated by the way browsers download and prompt such files. This means that even servers can't always tell what happened. There might be some specific work-arounds for a few specific cases, but they are not pretty or simple.

You could force your users to "re-upload" a downloaded file with an <input type=file> to validate it, but that's cumbersome at best, and the local file browse dialog could be alarming to some. It's the only sure-fire method to ensure a download, but for non-sensitive applications its very draconian, and it won't work on some "mobile" platforms that lack file support.

You might also try watching from the server side, pushing a message to the client that the file was hit on the server. The problem here is that downloads start downloading as soon as the Open/Save dialog appears, though invisibly in the background. That's why if you wait a few moments to "accept" a large file, it seems to download quickly at first. From the server's perspective, the activity is the same regardless of what the user does.

For a huge file, you could probably detect that the whole file was not transferred, which implies the user clicked "cancel", but it's a complicated syncing procedure pushing the status from backend to client. It would require a lot of custom programming with sockets, PHP message passing, EventSource, etc for little gain. It's also a race against time, and an uncertain amount of time at that; and slowing down the download is not recommended for user satisfaction.

If it's a small file, it will physically download before the user even sees the dialog, so the server will be useless. Also consider that some download manager extensions take over the job, and they are not guaranteed to behave the same as a vanilla browser. Forcing a wait can be treacherous to someone with a slow hard drive that takes "forever" to "finish" a download; we've all experienced this, and not being able to continue while the "spinny" winds down would lower user satisfaction, to put it mildly.

In short, there's no simple way, and really no way in general, except for huge files you know will take a long time to download. I've spent a lot of blood sweat and tears trying to provide my download.js users the ability, but there are simply no good options. Ryan dahl initially wrote node.js so he could provide his users an upload progress bar, maybe someone will make a server/client package to make it easy to do the same for downloads.

detecting when the File download popup is closed

I had to work on this kind of issue, on another project. I finally found a smart solution, as explained in another Stackoverflow question.

The explanation is given in the following post: http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser

The idea is to "simply" use a cookie to define when the file is downloaded.

Force showing the Save as dialog box when downloading a file

Yes, and it's called showSaveFilePicker().

This is part of the File System Access API, which is still a draft, but is already exposed in all Chromium browsers.

This API is quite powerful and will give your code direct access to the user's disk, so it is only available in secure contexts.

Once the Promise returned by this method resolve, you'll get access to an handle where you'll be able to access a WritableStream to which you'll be able to write your data.

It's a bit more complicated than download, but it's also a lot more powerful, since you can write as stream, not needing to have the whole data in memory (think recording a video).

In your case this would give

async function handleSaveImg(event){
const image = await new Promise( (res) => canvas.toBlob( res ) );
if( window.showSaveFilePicker ) {
const handle = await showSaveFilePicker();
const writable = await handle.createWritable();
await writable.write( image );
writable.close();
}
else {
const saveImg = document.createElement( "a" );
saveImg.href = URL.createObjectURL( image );
saveImg.download= "image.png";
saveImg.click();
setTimeout(() => URL.revokeObjectURL( saveImg.href ), 60000 );
}
}

Here is a live demo, (and the code).

How to trigger a file download when clicking an HTML button or JavaScript

For the button you can do

<form method="get" action="file.doc">
<button type="submit">Download!</button>
</form>

What's the purpose of the 'download' file which is downloaded by the browser when I make a request to 'localhost:3306'?

You are telling the browser to download a page through a mysql connection. The browser sends a request, and mySQL does not understand it (because it expects its own protocol, not HTTP), so it answers with a list of capabilities told in its own protocol (some binary jitter). The browser gets this response and because it is not correctly identified as a webpage (remember, the response is not HTTP) it cannot assume better than to offer it as a file, so it says this is the unnamed file "download" and puts the response into that. That's what you see. You're forcing a chinese into a conversation with a french ... don't expect sane results ;)



Related Topics



Leave a reply



Submit