ASP - Force file download
ASP Best Practices
Cause the browser to download a file rather than opening it.
Date : 2006-08-04
Many times when serving dynamic data to users we have issues with different browsers and different systems. One of the common problems we run into is how different browsers handle downloading files. One system will open a file for editing in an application and another will pop up a download dialog giving the user a chance to save the file on their system. This issue usually has to do with settings on the users computer but fixing each users computer to handle these downloads the way we want is out of the question. Instead we have to come up with a way to fix this problem with our code. This article will focus on getting the browser to allow download of a file rather than opening.
For that purpose here is an ASP script that will accept 2 URL variables: file and name.
It will then open “file” and serve it as an attachment rather than inline so that browsers will automatically open a download dialog giving the user the option of where to save the file.
The "file" variable tells the script what file to open. The "name" variable is what the downloaded file will be called. Many times this concept will be used for downloading reports that may contain dates or other specifically identifying information which can be added to the filename.
sFile = request.querystring("file")
sPath = "C:\Inetpub\Files" & sFile
sName = request.querystring("name")
ContentType = "application/x-msdownload"
Response.Buffer = True
Const adTypeBinary = 1
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition", "attachment; filename=""" & sName & """"
Response.Charset = "UTF-8"
Response.ContentType = ContentType
Set objStream = Nothing
Now this code is pretty simplified and has no error checking which I highly recommend before putting this into use but the concept should be fairly clear from this. Using HTTP headers we tell the browser to force a download as well as telling it what to call the file.
If you were to save this script as download.asp then it would be called like this:
(Notice I've added the forward slash here because it's not added in the script.)
More likely you will direct this script to a script that creates some kind of report that may need variables passed to it as well, so you may want to rearrange how this is called, but this should get you started.
You may have seen similar code before but notice when adding the "Content-Disposition" header I use "attachment; filename=""" & sName & """". Most people will leave out the quotes around the file name but this can cause trouble with downloading files with spaces in their file names from the Firefox broswer. Otherwise Firefox will cut the filename off at the first space it finds.
Be sure to add error correcting to this code before putting it into use or someone could use it to download just about anything from your server.
... security? This script has the potential for abuse. If files in the "C:\Inetpub\Files" need to be protected in some way (pay-only downloads, for instance), then nothing stops a user from brute forcing his/her way to getting those files.
Imagine a malicious user who wants your protected downloads creating a script that constantly requests URLs like this:
Given the opportunity to run long enough, and through various permutations of each URL requested, the files the cracker is after will be found.
If someone out there has a great abstraction scheme to prevent this, I'd love to hear it. I'm trying to build a dynamic download script myself which streams binary content to a user's browser.
This is a great example but as Nic pointed out you want to modify your code to not accept the file name as a parameter. In my implementation I am accepting only an id and I pull the path and file information from that. The security of each file isn't a big issue since the users who are authorized to use my application can download whatever they want all day long.
Totaly true... The best would be to store the file name elsewhere. This is just provided as an example of how to approach such a problem but we appreciate you adding in the reminders about security... can't be to safe!