Your Web browser is set up to handle all kinds of documents. For example,
when you open an .html page from a Web site,
the browser knows it should parse this file, and display its rendered contents
onscreen. The same is true for images; when you click on a link that directly
links to an image, the image will be displayed in the browser.
This default behavior may not always be what you want. In some scenario's,
it's useful to have the user download and save the file, instead of displaying
it in the browser. This is a common requirement for files like images,
Word documents, spread sheets and so on. This article will demonstrate
you how you can force the client browser to present the Save As dialog, so
your users can download the file and save it on their local hard disk.
Update - 02/11/2004
On 02/05/2004, Johnson Davis e-mailed me a work around for the problems with Netscape browsers like Netscape 7.0. If you move the download file to a sub folder, called /Downloads for example, and then make the download file the default file for the folder (in IIS this is usually done by renaming the file to default.asp, but you could also change the IIS settings so it uses your filename as the default file), the browser will look at the proposed attachment name instead of the name of the download file. So, in short, this is what you need to do:
- Create a folder called /Downloads
- Move the download file for this article (DownloadFile.asp) to the new Downloads folder and rename it as Default.asp
- Request the file in the browser by using http://YourServer/Downloads/ (note the absence of the file name, Default.asp)
Netscape will now offer the correct filename in the Enter name of file to save to...
dialog. This work around also works fine in other browsers, like Internet Explorer and Opera.
Thanks for the tip, Johnson!
The sample code presented in this article uses an ADODB.Stream
object which is available in ADO since version 2.5. All sample code is in ASP, so obviously you need a server running ASP.
The Complete Code
You can take a look at the complete code by following this link
. It will open in a new browser window, so it's easy to follow along with the explanation.
Forcing the download
To force the browser to display the Save As
dialog, you'll need to fool it a bit. When you open a file in your browser by clicking a link or by typing in an URL in the Address bar, the browser examines the content type of the file you are requesting. Based on this content type, the browser determines what action to take. It searches a list of "registered applications" to see if one of them is set up to handle the requested content type.
If, however, you pass the browser a content type it doesn't know about, it automatically presents you with the Save As
dialog. Changing the content type is easy in ASP; simply set the ContentType
property of the Response object to application/x-unknown
Response.ContentType = "application/x-unknown"
Once you have set up the content type, you can pass the name for the download to the browser as well. This name will be presented as the default name for the download. The user can change this name, however. The following code block declares two variables; One for the full name of the file you want to send to the browser. In this case, the code will send a Microsoft Word document to the browser. The other variable will hold the name as it appears in the Save As
dialog in the browser:
FileName = "MyWordDocument.doc"
FullFileName = "C:\Webfiles\MyWordDocument.doc"
With the file names done, it's time to set the name for the file download. You'll need to use the AddHeader
method of the Response
object to do this. The chr(34)
is used to send a double quote to the browser.
method will write out a a variant array of unsigned one-byte characters. To get this Variant array, you can use an ADODB.Stream
object. For easier access to the Stream
object, I created a function called GetBinaryFile
that instantiates and initializes this object. As a parameter it expects the full location of the file on disk, for example: C:\Webfiles\MyWordDocument.doc
. For the sake of simplicity, the function itself is included in the ASP page, but you can place this function in an include file, so other pages can access it as well.
Response.Addheader "Content-Disposition", _
"attachment; filename=" & chr(34) & FileName & chr(34)
method creates an instance of the ADODB.Stream
object by calling Server.CreateObject
and passing it the progID of ADODB.Stream
. The stream is opened and its type set to adTypeBinary
(to indicate you're sending a binary file, not plain text). The LoadFromFile
method will load the file in FileSpec
from disk, and then the Read
method will read its entire contents. Because this code is executed in a function, you shouldn't send the output of the Stream to the Response object directly. Instead, it is returned it from the function, by setting the functionname equal to the result of the Read()
method (GetBinaryFile = objStream.Read()
Function GetBinaryFile(ByVal FileSpec)
Const adTypeBinary = 1
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
GetBinaryFile = objStream.Read()
Set objStream = Nothing
The calling code
will then use the BinaryWrite
method to stream the file to the browser:
Providing Access to the File
This example uses a hard coded filename for the file you want to stream to the browser. In a real site, this is not a very useful solution.
Instead, you can make this page dynamic so you can pass it the ID
of a file you want to download through the QueryString
. You can then transform this ID
into a filename through a database lookup, a textfile, a Select Case
statement, or any other solution you can come up with. The following code demonstrates the general principle:
FileID = Request.QueryString("ID")
If Len(FileID) > 0 Then
' Pass the ID to a database and retrieve the filename
' FullFileName = Get the FileName from the Database
' Rest of the download code with the GetBinaryFile method goes here.
If you save the file with the download code as DownloadFile.asp
, you can the call this page like this:
<a href="Download.asp?ID=33">Download this File Now</a>
<a href="Download.asp?ID=34">Or Download this other File Now</a>
As you can see, the ID
of the file is passed to DownloadFile.asp
. Inside that file, the ID
is used for a database lookup that retrieves the full filename
Added Benefits of Using a Stream Object
By sending the file to the browser using the Stream object, it's easier to secure your files. Usually, when you want to provide a file your user can download, the file must be within the scope of your Web site, for example www.yoursite.com/Downloads/YourFile.doc
. This means people who know the URL of the file, can download it directly. If you want to protect the file, you can ask for a username and password, before you redirect your users to this URL. If, however, people already know the URL or can guess its name, they can circumvent your protection mechanism. All they need to do is type in the URL of the file directly and they can get access to it.
With the solution presented here, it's easier to block access to your file. All you need to do is check the user credentials (or any other business rules you may be using) at the top of the DownloadFile.asp
. If you don't want your user to continue, simply redirect them away from the download file, as shown in the following pseudo code:
' Check User Rights Here
If UserOK Then
' Use the ID from the QueryString to lookup the FileName
' Stream the File to the Browser
This way, you users won't be able to access the file if they are not allowed to download it. Instead, they will be redirected to the page: NoRights.asp
Disadvantages of the Stream Method.
Not all browsers will handle the proposed filename correctly. When you download the file in Netscape 6.2 for example, this is what you'll see:
Netscape thinks its downloading an ASP file, instead of a Word Document. As soon as you click Save this file to Disk
and then click OK
, Netscape will use the proposed filename (MyWordDocument.doc
) for the download.
Each browser deals with this differently; Mozilla and Netscape 7, for example, use the proposed filename, but append an .asp
extension to it, as shown if the following figure (from Mozilla 1.4):
In fact, the problem with these browsers is even worse as they also use this .asp
extension in the proposed filename in the Enter name of file to save to
dialog box. Your users will need to manually rename the file by removing the additional extension to make it a valid file. More recent versions of Mozilla (version 1.6) handle the downloaded file correctly, and propose the MyWordDocument.doc as the filename.
The method to download files presented in this article can be useful in a number of circumstances. First of all, it will allow your users to download a file, instead of having it opened within their browser.
Second, it allows you to put a tighter security mechanism in place; by validating the user before you stream the file, you can easily find out whether the user has access to the file.
The only drawback is that not all browsers handle the filename of the download correctly. If wide browser support is important to you, this solution is not very suitable. In other scenario's, like a company Intranet where you control the browser, this is an excellent way to control the files users can download from your site.