Classic ASP File Upload: A Complete Step-by-Step Tutorial

Everything you need to accept a file from a browser in Classic ASP, from the form markup to saving the file on disk.

Why file upload is harder in Classic ASP than it looks

Every other form field in Classic ASP arrives in Request.Form. A file does not. The moment you add enctype="multipart/form-data" to a form — which you must, because without it the browser sends only the file name, not its bytes — the ASP runtime stops parsing the request body for you. Request.Form comes back empty, including for the plain text fields that used to work.

That single design decision is the reason "how to upload a file in ASP" has never had a one-line answer. The raw body is still available through Request.BinaryRead, but it hands you an untyped byte array containing MIME boundaries, per-part headers, and the file contents interleaved. Turning that into a saved file is your job.

Step 1: the HTML form

Three things matter here and nothing else does:

<form id="form1" method="POST" enctype="multipart/form-data">
    <input type="file" name="myfile" />
    <input type="submit" value="Upload" />
</form>
  • method="POST" — a GET form cannot carry a file body.
  • enctype="multipart/form-data" — without it you receive the file name as a string and nothing else. This is the single most common cause of "my upload does nothing".
  • type="file" with a name — the name is how you find the part on the server.

Step 2: what actually arrives on the server

It helps to see the request body once. A single-file post looks roughly like this:

Content-Type: multipart/form-data; boundary=---------------------------7d5a2

-----------------------------7d5a2
Content-Disposition: form-data; name="myfile"; filename="photo.jpg"
Content-Type: image/jpeg

<raw binary bytes of photo.jpg>
-----------------------------7d5a2--

To save photo.jpg you have to read the boundary token out of the Content-Type header, scan the body for it, parse the part headers, find the blank line that separates headers from content, and copy every byte between there and the next boundary — without letting VBScript's string functions mangle the binary along the way.

Step 3 (the hard way): Request.BinaryRead

A minimal hand-rolled parser looks like this. It works, and it is worth reading once so you know what a component is doing for you:

<%
Dim byteCount, binData
byteCount = Request.TotalBytes
binData   = Request.BinaryRead(byteCount)   ' entire upload, in memory

' RSTRING conversion so we can use InStrB / MidB on the bytes
Dim rawText
rawText = BytesToString(binData)

' 1. pull the boundary out of the content type header
Dim boundary
boundary = Request.ServerVariables("HTTP_CONTENT_TYPE")
boundary = Mid(boundary, InStr(boundary, "boundary=") + 9)

' 2. locate the part, its filename, and the start of the binary payload
' 3. MidB() out the bytes between the headers and the closing boundary
' 4. write them with an ADODB.Stream
%>

The catch: Request.BinaryRead loads the whole post into server memory before your first line of code runs. A 500 MB upload needs 500 MB of RAM in the IIS worker process, plus another copy while you slice it. This approach is fine for a 200 KB avatar and completely unusable for anything large. See uploading large files in Classic ASP for what to do instead.

Step 4 (the old way): a COM component

For years the standard answer was to install a compiled component — ASPUpload, SA-FileUp, AspSmartUpload — and let it parse the stream. That works well, but it needs regsvr32 on the server, which means:

  • You need administrator access to the box. Most shared hosts will not do it.
  • Moving the site to a new server means re-registering, and remembering that you had to.
  • Licences are usually per-server, so a staging box costs extra.

Pure ASP file upload without components covers the alternative in detail.

Step 5 (the practical way): a pure ASP upload script

ASP Uploader is written entirely in Classic ASP and JavaScript. You copy a folder into your site, include one file, and instantiate the object. There is nothing to register and nothing for the visitor to install.

<%@ Language="VBScript" %>
<!-- #include file="aspuploader/include_aspuploader.asp" -->
<html>
<body>
<form id="form1" method="POST">
    <%
    Dim uploader
    Set uploader = new AspUploader
    uploader.Name = "myuploader"
    uploader.MaxSizeKB = 10240                                  ' 10 MB ceiling
    uploader.InsertText = "Upload File (Max 10M)"
    uploader.AllowedFileExtensions = "*.jpg,*.png,*.gif,*.zip"
    %>
    <%= uploader.GetString() %>
</form>
</body>
</html>

Note what is not there: no enctype, no <input type="file">. GetString() renders the button, the queue, and the progress bar, and the file travels on its own background request rather than as part of your form post.

Reading the uploaded file after the post

When the form posts back, the field named after your uploader contains a "/"-separated list of GUIDs, one per uploaded file. Exchange each GUID for a file object:

<%
If Request.Form("myuploader") & "" <> "" Then
    Dim list, i, mvcfile
    list = Split(Request.Form("myuploader"), "/")
    For i = 0 To UBound(list)
        Set mvcfile = uploader.GetUploadedFile(list(i))

        Response.Write mvcfile.FileName & " (" & mvcfile.FileSize & " bytes)<br/>"

        ' keep it:
        mvcfile.MoveTo Server.MapPath("uploads/" & mvcfile.FileName)
    Next
End If
%>

The important members are FileName, FileSize, MoveTo (move out of the temp folder) and CopyTo (keep the temp copy). Anything you do not move is cleaned up automatically.

Saving straight to a folder

If you do not need to inspect the files at all, set SaveDirectory and the script writes them for you as they arrive:

<%
Set uploader = new AspUploader
uploader.Name = "myuploader"
uploader.MultipleFilesUpload = true
uploader.SaveDirectory = "savefiles"     ' relative to the current page
uploader.Render()
%>

Step 6: the server-side checklist before you go live

  1. Write permission. The IIS application pool identity (usually IIS AppPool\YourPoolName) needs Modify on the upload folder. Nothing else does.
  2. No execute permission. Set the upload folder's handler mapping to none so a stored .asp file can never run. This is not optional.
  3. Validate on the server, not just the browser. Client-side checks are a usability feature; an attacker skips them entirely. See validating file size and type.
  4. Never trust the supplied file name. Strip paths, strip .., and prefer a name you generate. See the security checklist.
  5. Raise the IIS limits if you accept big files. maxRequestEntityAllowed and uploadReadAheadSize both cap uploads long before your code sees them.

Frequently asked questions

Why is Request.Form empty when I add a file input?

Because the form is now multipart/form-data and Classic ASP does not parse that encoding. Every field — text fields included — has to be read out of the raw body. A component or upload script gives them back to you.

Can Classic ASP upload files without a component?

Yes. Either parse Request.BinaryRead yourself, or use a pure ASP upload script such as ASP Uploader, which is plain .asp files you copy into the site.

What is the maximum file size Classic ASP can accept?

By default IIS caps a request body at 200 KB (maxRequestEntityAllowed). Raising it lets you go much higher, but an in-memory BinaryRead will still exhaust the worker process on large files. Chunked uploading removes the ceiling entirely.

Do visitors need Flash, Silverlight or a browser plug-in?

No. Modern browsers select and upload multiple files natively through the HTML5 File API.

Skip the plumbing

ASP Uploader does everything on this page out of the box: multi-file selection, a real progress bar, client and server validation, chunked large-file transfer, and no COM component to register. Drop the folder on your server and add one include line.

Download the free trial Try the live demo Pricing