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:

Download

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.

ASP Code

<%@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
%>

55 Responses to Downloading any file using ASP, FSO and the ADODB Stream object

  • Phillipe Calmet Williams

    Hello there…

    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.Clear
    Response.Write(“File extension not supported.”)
    Response.End
    ————-

    Thank you for the useful code.

    Regards.

    p.s.: Can I include your script in a “classic asp framework” that I’m coding? :)

    • Evagoras Charalambous

      @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.

  • Salih

    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???

    thankss…

    • Evagoras Charalambous

      @Salih,

      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:

      ftp://host:port/path
      OR
      ftp://user:password@host:port/path
      
  • Stephane Demers

    Hello!
    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.
    Thanks!

    • Evagoras Charalambous

      @Stephane Demers

      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?

  • shiroj Haris

    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.

    Thanks ,
    Shiroj

    • Evagoras Charalambous

      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.

  • not

    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?

    • Evagoras Charalambous

      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>).

      • not

        i copy your code for test because i need this code… i just change strpath parameter… i did not use querystring…
        my code is

        strpath="test.rar"

        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…

        • Evagoras Charalambous

          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.)?

  • mark

    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

  • mark

    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

    • Evagoras Charalambous

      Don’t use any quotes. Try something like this, where the banner.jpg file is located at the root of the website:
      http://www.mysite.com/download.asp?file=/banner.jpg

  • mark

    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

    • Evagoras Charalambous

      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.

  • Bob

    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.

    • Evagoras Charalambous

      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.

  • mark

    What is the Maximum file size we can download?

    • Evagoras Charalambous

      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.

      • mark

        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

        • Evagoras Charalambous

          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.

  • Greg

    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.

    • Evagoras Charalambous

      I think you can remove line 54 above which reads:

      Response.BinaryWrite(objStream.Read)

      and replace it with something like this:

      Do While Not objStream.EOS
      	Response.BinaryWrite objStream.Read(3670016)
      	Response.Flush
      Loop

      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.

  • john

    user name: windsorjohn220@gmail.com
    password: 268268

    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

    • Evagoras Charalambous

      I logged into the site and tried your download. When I click on a link I get something like this in the URL:

      http://windsorjohn-001-site1.smarterasp.net/download.asp?file=car%2Ejpg

      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:

      http://windsorjohn-001-site1.smarterasp.net/download.asp?file=/images/downloads/car.jpg
    • Evagoras Charalambous

      Is posting that username/password here safe? I can edit your comment and delete that for you if you like.

  • GarryBrown

    Thanks for the information. Also try Long Path Tool. It helped me with Error 1320 in Win 7. :)

  • Henry

    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

    • Evagoras Charalambous

      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)

  • Henry

    Encoding does not seem to work

    • Evagoras Charalambous

      I believe Server.MapPath will fail if your filename contains an ampersand (&). See here for more details:
      http://classicasp.aspfaq.com/files/directories-fso/why-do-i-get-an-invalid-path-character-error.html

      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.

  • Henry

    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

  • Neil Johnston

    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.

  • Neil Johnston

    That worked, I used the relative path. Thanks so much for your script.

  • sar

    Excellent!! Helped me a lot.

  • Daniel Hall

    Hi Evagoras,

    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!”
    Response.Write End
    End If

    Please do correct me if I’m wrong.

  • Daniel Hall

    Hello again,

    I’ve just seen this in your code…

    ElseIf InStr(strPath, “..”) > 0 Then
    Response.Clear
    Response.Write(“Illegal folder location.”)

    Foot-in-mouth moment! My apologies!

  • mary

    Hi,

    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 ?

    Thanks,
    Mary

    • Evagoras Charalambous

      @mary,

      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.

  • Michael Riley

    Evagoras,

    Thank you for this script. Will google index this page? If google does index this page what will the indexed reference look like?

    • Evagoras Charalambous

      @Michael Riley,

      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?

  • Roger

    Hi
    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?

  • roger

    hi
    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.

    Roger

    • Evagoras Charalambous

      @roger,

      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:
      http://www.adamwlewis.com/articles/iis-7-not-serving-files-4047-error

      Summary of changes here:

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <system.webServer>
          <security>
            <requestFiltering>
              <fileExtensions allowUnlisted="true" >
                <remove fileExtension=".mdb" />
                <add fileExtension=".mdb" allowed="true"/>
              </fileExtensions>
            </requestFiltering>
          </security>
        </system.webServer>
      </configuration>
      

      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).

  • Roger

    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.

    Cheers

    Roger

    • Evagoras Charalambous

      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.

  • GiovPoll

    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.Open
    DownLoad.Type = adTypeBinary
    DownLoad.LoadFromFile Server.MapPath(InputFile)

    Ext=Right(InputFile, 5)
    Dove=InStr(Ext,”.”)*1
    if IsNull(Dove) then Response.end
    if Dove=0 then Response.end

    Ext=””
    Ext=lcase(Right(InputFile, 6-Dove))

    Select Case Ext
    Case “.zip”
    ContentType = “application/zip”
    Case “.7z”
    ContentType = “application/x-7z-compressed”
    Case “.htm”, “.html”
    ContentType = “text/html”
    Case “.txt”
    ContentType = “text/plain”
    Case “.doc”, “.rtf”
    ContentType = “Application/msword”
    Case “.pdf”
    ContentType =”application/pdf”
    Case Else
    ContentType = “application/octet-stream”
    End Select

    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
    Response.BinaryWrite DownLoad.Read(3670016)
    Response.Flush
    Loop

    Download.Close
    Set DownLoad=nothing

  • Hamilton

    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!

  • Wittawat

    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

  • Emi

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *