Monday, 2 February 2009

"Maximum request length exceeded" error

I have an aspx page using standard FileUpload control. When I tried to upload a file bigger than 4MB the page was not displayed or the following error message appeared: "Maximum request length exceeded". This is caused by maximal allowed size of request accepted by the server. Since the uploaded file is sent in request's body the whole request is even bigger than the file itself.

I've seen some solutions using Application_Error handler defined in Global.asax. This approach is quite straightforward and seems to be a way to go but unfortunately it didn't work for me - the page was still not displayed and the error was not handled.

Solution:
First, set the size of request accepted by the server to maximum (1GB) in web.config. Then, define a custom HttpModule that would check request's length (also in web.config):
<system.web>
<httpRuntime maxRequestLength="102400" />
<httpModules>
<add name="RequestLengthCheck"
type="MyNamespace.RequestCheckModule, MyLibraryName" />
</httpModules>
</system.web>
Now you have to implement the HttpModule that would check request's size and redirect to an error page if it's too big:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace MyNamespace
{
public class RequestCheckModule : IHttpModule
{
public void Init(HttpApplication app)
{
app.BeginRequest += new EventHandler(app_BeginRequest);
}


void app_BeginRequest(object sender, EventArgs e)
{
HttpContext context = (HttpApplication)sender).Context;

if (context.Request.ContentLength > 4096000)
{
IServiceProvider prov = (IServiceProvider)context;
HttpWorkerRequest wr =
(HttpWorkerRequest)prov.GetService(typeof(HttpWorkerRequest));

// Check if body contains data
if (wr.HasEntityBody())
{
// get the total body length
int reqLength = wr.GetTotalEntityBodyLength();
// Get the initial bytes loaded
int initBytes = wr.GetPreloadedEntityBody().Length;

if (!wr.IsEntireEntityBodyIsPreloaded())
{
byte[] buffer = new byte[512000];
// Set the received bytes to initial
// byted before start reading
int recBytes = initialBytes;
while (reqLength - recBytes >= initBytes)
{
// Read another set of bytes
initBytes = wr.ReadEntityBody(buffer, buffer.Length);
// Update the received bytes
recBytes += initBytes;
}
wr.ReadEntityBody(buffer, reqLength-recBytes);
}
}
// Redirect the user to an error page.
context.Response.Redirect("Error.aspx");
}
}

public void Dispose()
{
}
}
}
I've found this piece of code here. It works perfect. The only thing I don't understand is why the whole request needs to be read for this to work? I've tried to make the redirection right after wr.GetTotalEntityBodyLength(); but it didn't work. Anybody knows why?

2 comments:

Anonymous said...

Hi. do you know anywhere i can find this code in VB instead of C#. I have tried to convert it myself but with no joy. I am quite new to all this ASP.Net code.

Thanks

Tommy

Anonymous said...

I assume that it needs to be read so that the current Request length
(which is higher than permitted) is removed which would then allow the next request to work.