Often you will want a user to download / save a TXT, XLS, GIF, HTML or other file type that the browser would normally simply open and display within the browser (either from an HREF, a response.redirect, or a save target as). Here is one method I've used to force a prompt, in a file called download.asp:
<% Response.ContentType = "application/x-unknown" ' arbitrary fn = "whatever.jpg" FPath = "c:\" & fn Response.AddHeader "Content-Disposition","attachment; filename=" & fn Set adoStream = CreateObject("ADODB.Stream") adoStream.Open() adoStream.Type = 1 adoStream.LoadFromFile(FPath) Response.BinaryWrite adoStream.Read() adoStream.Close Set adoStream = Nothing Response.End %> |
And from the page where you want to launch this Save As dialog, you can do any method of redirection. Here are a few examples:
<% response.redirect("download.asp") %> |
| <meta http-equiv='refresh' content='0;url=download.asp'> |
| <a href='download.asp'>Download whatever.jpg</a> |
<script> window.location.replace('download.asp'); </script> |
Now keep in mind that the user can just decide to open it if they choose.
One thing to keep in mind, is to avoid adding a custom cache-control header; the technique in
Article #2022 could cause these downloads to fail.
Some users have found that Internet Explorer prompts users with two open/save as dialogs. This is likely because you have sent the filename in both the ContentType and the AddHeader/Content-Disposition headers. To resolve the issue, use only the AddHeader variant. (See
KB #238588 for more information.)
Many people have complained that larger files simply do not work. You might see the following error messages from Internet Explorer:
Unable to allocate required memory --or Not enough storage is available to complete this operation. --or Internet Explorer cannot download <file> from <server>. |
You can try code like this instead, which sets response.buffer to false, sets a high server.scriptTimeout value, sets an explicit content-length header, and streams the file in chunks instead of all at once. Make sure you do not set an alternate character set using Response.CharSet.
<% Response.Buffer = False Server.ScriptTimeout = 30000 Response.ContentType = "application/x-unknown" ' arbitrary fn = "whatever.jpg" FPath = "c:\" & fn Response.AddHeader "Content-Disposition", "attachment; filename=" & fn Set adoStream = CreateObject("ADODB.Stream") chunk = 2048 adoStream.Open() adoStream.Type = 1 adoStream.LoadFromFile(FPath) iSz = adoStream.Size Response.AddHeader "Content-Length", iSz For i = 1 To iSz \ chunk If Not Response.IsClientConnected Then Exit For Response.BinaryWrite adoStream.Read(chunk) Next If iSz Mod chunk > 0 Then If Response.IsClientConnected Then Response.BinaryWrite adoStream.Read(iSz Mod chunk) End If End If adoStream.Close Set adoStream = Nothing Response.End %> |
One other thing you might have to experiment with. To get the filename correct, try any of the following AddHeader lines... different versions of IE require a different command in order to override the filename. You might have to send a custom line depending on the version of Internet Explorer being used by the client.
Response.AddHeader "Content-Disposition", "attachment; filename=" & fn Response.AddHeader "Content-Disposition", "attachment; filename=" & fn & ";" Response.AddHeader "Content-Disposition", "inline; filename=" & fn Response.AddHeader "Content-Disposition", "inline; filename=" & fn & ";" Response.AddHeader "Content-Disposition", "filename=" & fn Response.AddHeader "Content-Disposition", "filename=" & fn & ";" |
See
Article #2129 for more information. Some Microsoft articles, for further reading:
KB #260519 HOWTO: Raise a "File Download" Dialog Box for a Known MIME Type
KB #262042 FIX: Content-Disposition: Attachment Saves Wrong Filename for Unknown Extension
KB #267991 FIX: "Content-Disposition: Attachment" Fails for Known Content Types
KB #279667 FIX: Content-Disposition Attachment Header Does Not Save File
(Also see
Security Bulletin MS01-015.)
KB #816868 Error Message: "Internet Explorer Cannot Download a File"