How to Upload Large Files in Classic ASP (2 GB and Beyond)

Memory limits, IIS ceilings, timeouts — and the chunked approach that sidesteps all three.

Three separate walls, three separate fixes

"Large uploads fail in Classic ASP" is really three unrelated problems wearing the same error page. You have to identify which one you are hitting before changing anything, or you will raise a limit that was never the constraint.

WallSymptomFix
IIS request-size limitsInstant HTTP 500 or 404.13 — the upload never starts movingRaise maxRequestEntityAllowed and maxAllowedContentLength
MemoryUpload runs, then the app pool recycles or throws "Out of memory"Stop buffering the whole file — stream or chunk it
TimeoutsFails at roughly the same elapsed time every attempt, regardless of fileRaise Server.ScriptTimeout and the connection timeout

Wall 1: the IIS ceilings

Classic ASP ships with a request body limit of 200 KB. Not 200 MB. This surprises people constantly, because a 150 KB test image works and a 3 MB one returns 500 with nothing in the browser to explain it.

There are two independent limits, in two different places, and both apply:

<!-- web.config -->
<configuration>
  <system.webServer>

    <!-- The Classic ASP limit. Bytes. Default 200000 (~200 KB). -->
    <asp maxRequestEntityAllowed="2147483647" scriptTimeout="00:60:00" bufferingOn="true" />

    <security>
      <requestFiltering>
        <!-- The request-filtering limit. Bytes. Default 30000000 (~28.6 MB). -->
        <requestLimits maxAllowedContentLength="2147483647" />
      </requestFiltering>
    </security>

  </system.webServer>
</configuration>

There is a third limit that only shows up under specific configurations: uploadReadAheadSize, which controls how much of the entity body IIS reads before handing control to the handler. If uploads stall over HTTPS or behind certain modules, raise it:

appcmd set config -section:system.webServer/serverRuntime /uploadReadAheadSize:10485760 /commit:apphost

maxAllowedContentLength is a 32-bit unsigned value, so the hard ceiling is 4,294,967,295 bytes (4 GB) — and maxRequestEntityAllowed tops out at 2,147,483,647. If you need to accept files larger than that in a single request, you cannot. Chunking is the only route past it.

Wall 2: memory, and why raising limits is not enough

Suppose you set both limits to 2 GB and post a 1.5 GB file. Now this happens:

binData = Request.BinaryRead(Request.TotalBytes)   ' 1.5 GB allocated, right here

Request.BinaryRead materialises the entire request body in the worker process before your script continues. Then any parsing you do — MidB, string conversion, copying the payload out of the boundary wrapper — allocates again. Peak usage is comfortably two to three times the file size.

Ten concurrent 1.5 GB uploads is not a feature you can offer this way at any limit setting. The app pool will hit its private-memory recycle threshold and drop every in-flight request, including the nine that were fine.

The fix: chunked uploading

Instead of one enormous POST, the browser slices the file and sends fixed-size pieces — typically a few megabytes each — on separate requests. The server appends each piece to a temp file and forgets it. Consequences:

  • Peak server memory equals one chunk, not one file. A 20 GB upload costs the same RAM as a 4 MB one.
  • Every individual request is far below maxRequestEntityAllowed, so the IIS ceilings stop mattering.
  • Each request is short, so script timeouts stop mattering.
  • A dropped connection loses one chunk, not four hours of transfer — the transfer can resume.
  • You get real progress information for free, because you know exactly how many chunks have landed.

ASP Uploader does this automatically. There is no chunk-size property to reason about and no reassembly code to write — the file object you receive on postback is the complete file:

<%
Dim uploader
Set uploader = new AspUploader
uploader.Name = "myuploader"
uploader.MultipleFilesUpload = true
uploader.MaxSizeKB = 4194304                 ' 4 GB ceiling, enforced before transfer
uploader.InsertText = "Select a large file"
%>
<%= uploader.GetString() %>

<%
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))
        ' fully reassembled already - just move it where you want it
        mvcfile.MoveTo Server.MapPath("archive/" & mvcfile.FileName)
    Next
End If
%>

Setting MaxSizeKB also stops oversized files in the browser, before a single byte crosses the wire. Telling someone their 6 GB file is too big after a two-hour upload is a support ticket you can simply not have.

Wall 3: timeouts

A large upload on a slow connection can easily outlive the defaults. Four separate timers can kill it:

SettingDefaultWhere
Server.ScriptTimeout90 secondsTop of the ASP page, or the <asp> element
Connection timeout120 secondsIIS site → Advanced Settings → Limits
Idle time-out20 minutesApp pool → Process Model (recycles an idle pool mid-upload)
Regular time interval1740 minutesApp pool → Recycling
<% Server.ScriptTimeout = 3600 ' one hour, for this page only %>

Chunked uploads mostly sidestep this class of problem, because no single request is long-running. But the app pool idle timeout still deserves attention: if all your users do is upload, IIS can decide the pool is idle and recycle it. Set it to 0 for upload-heavy applications.

Do not forget what is in front of IIS

If the site sits behind Cloudflare, an F5, nginx, or an ARR reverse proxy, that device has its own body-size limit and its own timeout — and it will reject the request before IIS ever sees it. Common ones:

  • Cloudflare — 100 MB per request on Free/Pro plans. Chunked uploads stay well under it; a single 500 MB POST is rejected with a 413 no matter what IIS allows.
  • nginxclient_max_body_size, default 1 MB.
  • ARR — has its own request timeout, separate from IIS's.

Quick checklist

  1. Set maxRequestEntityAllowed and maxAllowedContentLength in web.config.
  2. Raise Server.ScriptTimeout on upload pages.
  3. Set the app pool idle time-out to 0.
  4. Check the proxy or CDN body limit in front of IIS.
  5. Confirm the drive holding the temp folder has room for the largest file plus headroom.
  6. Stop buffering whole files — use a chunked uploader so none of the above is load-bearing.

Frequently asked questions

What is the maximum upload size in Classic ASP?

In a single request, maxRequestEntityAllowed caps you at 2 GB and available memory caps you well below that in practice. With chunked uploading there is no practical limit beyond disk space.

Why does my upload fail at exactly 200 KB?

That is the default maxRequestEntityAllowed. Raise it in web.config.

Why does a large upload return 404.13?

Request filtering rejected the body as too long. Raise maxAllowedContentLength under requestLimits — this is a different limit from the ASP one and both must be raised.

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