In this article, we will see how to allow users to download any file from a web server by streaming it through ASP. They will see a prompt, giving them the option of opening or saving it, rather than simply opening it which is the default. We can achieve this using the FSO and ADODB objects.
The desired effect
There are times when you want users to download a file instead of opening it up in a browser; like images, text files, ASP code files, MS Office files like Powerpoint or Word files, etc. That’s easy to do for a ZIP file for example, but hard with a GIF or TXT. The reason is that anything that the browser recognizes as a valid format, it will open right away without giving you the option to save it. We want the user to receive a prompt though, asking them if they want to save or open the file, like below:
We can achieve the above for any file, by simply editing the Response that the browser receives from our web server. By editing the header and the content type, we can prepare the browser to accept binary streams, which would then save as attachments. So, it will always prompt the users to save the content.
<%@Language="VBScript"%> <%Option Explicit%> <%Response.Buffer = True%> <% On Error Resume Next Dim strPath strPath = CStr(Request.QueryString("file")) '-- do some basic error checking for the QueryString If strPath = "" Then Response.Clear Response.Write("No file specified.") Response.End ElseIf InStr(strPath, "..") > 0 Then Response.Clear Response.Write("Illegal folder location.") Response.End ElseIf Len(strPath) > 1024 Then Response.Clear Response.Write("Folder path too long.") Response.End Else Call DownloadFile(strPath) End If Private Sub DownloadFile(file) '--declare variables Dim strAbsFile Dim strFileExtension Dim objFSO Dim objFile Dim objStream '-- set absolute file location strAbsFile = Server.MapPath(file) '-- create FSO object to check if file exists and get properties Set objFSO = Server.CreateObject("Scripting.FileSystemObject") '-- check to see if the file exists If objFSO.FileExists(strAbsFile) Then Set objFile = objFSO.GetFile(strAbsFile) '-- first clear the response, and then set the appropriate headers Response.Clear '-- the filename you give it will be the one that is shown ' to the users by default when they save Response.AddHeader "Content-Disposition", "attachment; filename=" & objFile.Name Response.AddHeader "Content-Length", objFile.Size Response.ContentType = "application/octet-stream" Set objStream = Server.CreateObject("ADODB.Stream") objStream.Open '-- set as binary objStream.Type = 1 Response.CharSet = "UTF-8" '-- load into the stream the file objStream.LoadFromFile(strAbsFile) '-- send the stream in the response Response.BinaryWrite(objStream.Read) objStream.Close Set objStream = Nothing Set objFile = Nothing Else 'objFSO.FileExists(strAbsFile) Response.Clear Response.Write("No such file exists.") End If Set objFSO = Nothing End Sub %>
Just FYI, there is a little “problem” with your script: You can use it to download ANY file in your server, including ASP files, that might contain important information that you do not want people to know about (like username and password for a DB). To avoid this, you can add these lines to the “error checking” part:
ElseIf Right(strPath,4) “.jpg” Then ‘ …specify the file format(s) to allow download
Response.Write(“File extension not supported.”)
Thank you for the useful code.
p.s.: Can I include your script in a “classic asp framework” that I’m coding? 🙂
@Phillipe Calmet Williams:
Absolutely. You make a great point. If one was to add this to their site, then they should definitely think about restricting downloading certain types of files, and ASP files are probably the first ones. Thanks for pointing that out!
And feel free to use this in any way you find it useful. I am just glad I could help.
How can i download from other server.. because i have got bandwith problem and i put my files to other free ftp servers.. but i can not use this script to download from other servers…
are there some methods???
Of course you could use either pure ASP code or any free/paid components to FTP the file in the background from your FTP servers to our website, and then stream the file to your user like I show. You can look for examples online on how to FTP a file in the background using ASP – there are plenty out there.
However, that would result in your web server serving the file to the user and it would increase your bandwidth out, which is what you are trying to avoid in the first place, so I am not sure if there is a solution for you.
Why don’t you simply link to the FTP site for the download directly? You could do this using a READ-ONLY FTP account with a username and password, or a READ_ONLY FTP folder with no credentials:
Thanks for your code!
Do you know a way to track the success of the download? I made some research on Google, but so far, with the method you show, I found nothing useful.
Interesting idea. I have never tried it myself, and I think it would be hard to do. Without any tests, I am thinking of a couple of different scenarios for you here.
1) Perhaps break up the file into smaller chunks (pieces) and measure which chunks made it to the client. So, if your file is made up of 4 chunks, and a download was started, and the 3rd chunk was requested but not the 4th, then you can assume that 3/4 of the file was downloaded. This is not accurate and again, past the last but one chunk or for small files, you will never know if the full file was downloaded or not.
2) Use web sockets to capture the interaction between the server and the client and perhaps respond back to the server if a successful and complete download was made.
What do you think?
I want to add this script to enquiry form. when a person add the form like name,email,message and submit the button.After submitting automatically download pdf file. can u please help me for this code.
What are you having difficulty with? From what you describe above, you just want to add my code in the postback section of your page. You can check if something was posted using the REQUEST.QUERYSTRING for URL parameters or REQUEST.FORM for form variables. So, just just to make sure that your required fields (name, email, message, etc.) have been filled in and then include my code. Unless I am not understanding your requirements, it should work just fine.
i try to thsi code.. but everytimes i see “No file exist”.. the asp page on web site root and the file on web root.. but the file not found… :((( must i change something on my web server?
How are you passing the file to be downloaded into the code? If you doing so through a URL parameter, make sure you are escaping the characters. Watch out for strange filename characters or spaces. Post some code here if you are still having issues (you can paste code within <code></code>).
i copy your code for test because i need this code… i just change strpath parameter… i did not use querystring…
my code is
my asp file name is download.asp in web root and my file test.rar also in same place… i try to other files but i can take same mesaj…
if i will success about this code, i can customize and use this code…
I followed your scenario and placed the download file in the root folder together with a RAR file and then pointed the RAR file inside the download. Everything worked without any changes needed to the file. Something else must be preventing the script from working on your site. Have you tried to download another type of file (a JPEG, GIF, etc.)?
Hi, I am not sure exactly how to pass the parameter via the url.
This is how I am passing the filename
http://www.mysite.com/download.asp?file=“banner.jpg” and http://www.mysite.com/“download.asp?file=banner.jpg”
I have tried various options but just get a Server error 500 as a result
500 – Internal server error.
There is a problem with the resource you are looking for, and it cannot be displayed.
The http log shows this
2013-02-08 11:22:30 server ip address GET /download.asp file=”banner.jpg”|2|ASP_0140|Page_Command_Out_Of_Order 80 – my ip address HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+7.0;+Windows+NT+6.1;+WOW64;+Trident/5.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0;+InfoPath.3;+.NET4.0C;+.NET4.0E) ASPSESSIONIDAAQQDCTS=BAGJJGMBAJJPMJCPADCFOEHG;+ASPSESSIONIDSACBDCSB=PNCNMHGCBAHPDACDLCMKDHPJ;+ASPSESSIONIDSCBBDDSA=KLKBAJGCNPDMJLMJEBIFFHBN http://www.mysite.com/index1.asp http://www.mysite.com 500 0 0 1404 719 31
OK, I found the 500 error, I had some session check code in the first line of the asp and this broke the original code. With that out of the way, I must still be doing the linking wrong as the file is not being served
All I see in the log is
GET /download.asp file=”banner.jpg” error 200
Don’t use any quotes. Try something like this, where the banner.jpg file is located at the root of the website:
I have just tried that, using both /banner.jpg and just banner.jpg with the same results. Yes, the banner.jpg is sitting in the root
Please click >here< to download the video
Something else must be at play here. I just copied-pasted the code into a file called “download.asp” in the root folder of a new site, added a JPG called “banner.jpg”, and then called the JPG file from the download script just fine. It worked right off the bat for me.
I’ve been using your script for quite some time (successfully) – thank you! 🙂
Just came across a problem though – it can’t handle files larger than 4meg. You just get a “not found” error. Not sure the workaround yet.
This is usually caused by the maximum buffer size of 4GB (you DO mean GB right, and not MB like you mentioned) set by IIS and some older browsers.
There are ways around this. The easiest way is to increase the buffer size in IIS (see this Microsoft support article), or using the GUI: in server manager click on ASP, change buffer limit 4mb to 64mb, apply and restart.
Another way is to enable Response.Buffer and then read a large file in chunks and flush each part out using the Response.Flush command.
You could also try my code above and try switching off Response.Buffer, by adding something like this after the Response.Clear:
Response.Buffer = False
I haven’t actually tested any of the above, so let me know how it works for you.
What is the Maximum file size we can download?
Like I mentioned above, this is usually set at 2/4GB, and it’s a server setting which you can overwrite. See the link to the Microsoft support article I posted above.
Can we increase or overwrite the download size to 100gb in the server setting?if not as you mentioned “enable Response.Buffer and then read a large file in chunks and flush each part out using the Response.Flush command.” will this help to download 100gb file
100GB is a lot, although I suppose you could theoretically do it. It will all depend on the connectivity between the browser and your server for a successful download – the longer it takes for a download to finish, the more things that can go wrong. Try it and see how it works for you.
Hi there, thanks very much for this code, have had to search for a while to find something I can get working!
– Interestingly, I could only get this to work by adding “response.flush” after response.binarywrite.
– On my localhost, I have increased the buffer size so that I can use bigger files (only about 9mb needed for me), however, my webhost obviously has a 4mb buffer limit set. Any chance you could help point me towards how we can modify the script so that it can read 4mb chunks into the buffer, flushing each time? Using response.buffer=false doesn’t solve the problem.
I think you can remove line 54 above which reads:
and replace it with something like this:
That should break up your file in chunks of 3670016 bytes and avoid running into the 4GB limitation. I haven’t tested it myself, but something like that should work.
user name: email@example.com
Click Download File Information…Click any file for download
fail to here(never true): “If objFSO.FileExists(strAbsFile) Then”
show “No such file exists”
I can get right file name (strAbsFile path) when I use “response.write strAbsFile and response.end”. Can you help me? thank you
I logged into the site and tried your download. When I click on a link I get something like this in the URL:
So, you want to make sure that for one the “%2E” character is replaced with a simple “.” instead, and second, the link assumes that the JPG file is in the same folder as the “download.asp”, which apparently it is not. You need to figure out what the proper URL is for your images and add it in there. So, if for example the images are located under the “/images/downloads” folder on your site, you would use something like this:
Is posting that username/password here safe? I can edit your comment and delete that for you if you like.
Thanks for the information. Also try Long Path Tool. It helped me with Error 1320 in Win 7. 🙂
I am trying to copy picture files that have the ampersand (&) symbol in them
They are wedding pictures like “Henry&Mary.jpg”
When I try to copy them, it fails dues to the &
Is there anyway to circumvent this, I am using the following code (sample)
fromFolder = “C:\Projects\Reunion\CalPicTest”
toFolder = “C:\Projects\Reunion\CalPicDate”
picnameFull = “Henry&Mary.jpg”
picNameNew = “1965-Henry&Mary.jpg”
fso.CopyFile fromFolder & “\” & picNameFull , toFolder & “\” & PicNameNew
Appreciate any advice. Hopefully NOT one to rename files, there are over 400 of them and in addition other programs count on the presence of the & sign to distinguish regular pictures from wedding pictures
Have you tried encoding the symbol “&” to see if it works for you? You could do something simple like:
fromFolder = “C:\Projects\Reunion\CalPicTest”
toFolder = “C:\Projects\Reunion\CalPicDate”
picnameFull = “Henry&Mary.jpg”
picnameFull = Server.URLEncode(picnameFull)
picNameNew = “1965-Henry&Mary.jpg”
picNameNew = Server.URLEncode(picNameNew)
Encoding does not seem to work
I believe Server.MapPath will fail if your filename contains an ampersand (&). See here for more details:
Although you might not be calling Server.MapPath per se, perhaps the fso.CopyFile method is doing so behind the scenes and that’s why it doesn’t work.
A workaround might be to read the contents of your file into a ADODB.Stream object and then create a new file at the destination folder and write that stream into the file. I know it’s a long way of doing it, but it might work.
Thanks for the followup.
I have already decided to NOT have such a character in the name. That was probably a poor choice in the first place.
Your procedure is working fine for me
I uploaded your script and changed the strPath to a path for a file I know exists, when I run the script all I get is a blank window, no prompts, errors.
I am presuming I should get a dialog window asking where to save the file but I get nothing. Any suggestions. Thxs.
What is the path you added to the strPath variable? Try to use relative as well as absolute file paths:
That worked, I used the relative path. Thanks so much for your script.
Glad it worked out!
Excellent!! Helped me a lot.
Great script. Has saved me much time. With regards to Phillipe’s comments on restricting the file type. Even with this restriction in place would it still not be possible to download any files on the machine of that particular type?
Say for example, I had some personal photos in C:\Photos\ and this script was in C:\inetpub\wwwroot\, it would be possible to pass file=../../Photos/0001.jpg”?
I know its highly unlikely that someone would correctly guess that I had a photos folder on my C:\ drive with a file called 0001.jpg, but I think there needs to be a path check or restriction also. Maybe something along the lines of…
If objFile.ParentFolder.Path “C:\inetpub\wwwroot\images\” Then
Response.Write “No chance!”
Please do correct me if I’m wrong.
I’ve just seen this in your code…
ElseIf InStr(strPath, “..”) > 0 Then
Response.Write(“Illegal folder location.”)
Foot-in-mouth moment! My apologies!
🙂 No problem sir! Glad the code was helpful.
I’m currently trying to use this for a .xlsx file it works for every other type but not this one. Just wondering if you have ever managed to do this ?
I have not tried it with the newer Excel files, so I couldn’t say. It’s weird that it doesn’t work just for those types.
Thank you for this script. Will google index this page? If google does index this page what will the indexed reference look like?
If you mean the “download.asp” file, then that would depend on whether you have a meta tag in the HEAD of the document to index or not. You could also add it to the robots.txt file as not indexed, but that could be a potential security risk as devious people could see that file and use it to try to download stuff they shouldn’t.
If you mean the files to be downloaded, again that would depend if the files are on a public site or outside of the web root. If an indexing engine can get to a file, and you don’t ask it not to index it, it will do so – regardless if it’s an HTML page, a PDF document, an Excel or an MDB file.
Does that answer your question?
I’m trying your code out in my localhost (W7). When i anter an URL like “http://localhost/sample/download.asp?file=/db/accessfile.mdb”
i’m getting the reply telling me that “No such file exists.”.
But it is there.
What am i doing that’s not correct? I read earlier thet this does not support “xlsx”-files. Is it the same with Access-databases?
i made a posting the other day about a problem i have with your code, but it seems as if it has disappeared.
i have a MsAccess db file (3 MB) in a subfolder to the webroot in which the “download.asp” resides. When i’m trying to dl the file with “http://localhost/download.asp?file=/db/dbase.mdb rhe page just replies “No such file” (or something similar). If i move the file to the root i’m getting the same reply. If i try to dl a small text fileit works as expected.
Any ideas about what the problem might be? Does your code support dl from subdirs? Doesn’t Office files woerk, or what?
Looking forward for your reply.
If you are getting a 404 error, make sure to enable downloading MDB files on your IIS configuration. Here’s a good explanation of the possible issue and how to fix it:
Summary of changes here:
The same would apply for any type of files you are having an issue with – you would need to add the file extension permission in the web.config of the website (or machine.config of the server to change all the sites).
I’m not recieving a 404-error. In fact: I’m not recieving any errors what so ever EXCEPT this “No such file exists”.
I’m not so sure how to fix this due to the sad fact that my Web hotel won’t let me do anything with the web server. But I’ll check this out as soon as i return home.
Have you tried to add those extension handlers anyway? Since the file loading is wrapped in an IF FILE EXISTS statement (lines 37 and 58-61), you might not see the 404 error but it’s there. You could also remove that entire IF block to see what happens.
Gheia sas Evagoras,
j don’t succeed to download a compressed folder with more than one file.
When I try to decompress the folder the programm goes on error :
End-of-central-directory signature not found. Either this file is not a Zip file, or it constitutes one disk of a multi-part Zip file.
Thnak you for your attention, many greetings
‘ Scarica file
Set DownLoad = Server.CreateObject(“ADODB.Stream”)
DownLoad.Type = adTypeBinary
if IsNull(Dove) then Response.end
if Dove=0 then Response.end
Select Case Ext
ContentType = “application/zip”
ContentType = “application/x-7z-compressed”
Case “.htm”, “.html”
ContentType = “text/html”
ContentType = “text/plain”
Case “.doc”, “.rtf”
ContentType = “Application/msword”
ContentType = “application/octet-stream”
Response.Charset = “UTF-8”
Response.ContentType = ContentType
Response.AddHeader “Content-Length”, CStr(DownLoad.Size)
Response.AddHeader “Content-Disposition”,”attachment;filename=” & OutputFile
Do While Not DownLoad.EOS
Great script. Thanks a lot! Has saved me much time. I changed the script and insert a path. This way I do not show the real path to my visitor.
It is working fine!
Hello Evagoras Charalambous
I use your code to download exe file but I can not download exe file to succes
exe file size = 856 KB
Hi, I am trying to download a .epub file and gives a me a 0bytes file.
the strange thing is that if I try with a PDF which is in the same location it works.
I have a scenario where i have to provide the download count of a file, in that case if the User cancel the download, those i should not consider.
How can i get whether user saved or open or cancel. Is it Possible ?