Maximum Request Length Exceeded

Posted by Jason on December 11, 2008 at 9:52 am

It’s hard to believe how badly this is handled in IIS. Admittedly I’ve only tried it in IIS 6, but I see no evidence that it gets any better in IIS 7.

So here’s the problem – you create a website that allows the upload of images (or any file types for that matter). It’s very likely you’re going to want to limit the size of those uploads or you’ll end up in a world of pain when your users go and use up all your disk space. By default IIS allows upload sizes of 4Mb which is ample for image purposes. However, if someone uploads a file above that size you’re likely to want to notify them by telling them gently they’re an idiot for not reading the note above the file input field and then allow them to reselect a file.

But you can’t because the requests never gets to your page. IIS simply drops the request and seems to respond with nothing at all. That leaves the user looking at a ‘Web site could not be found’ error, which is misleading and just plain wrong.

And this is the situation I found myself in. Simply put, you can’t catch the HttpException in your code and recover gracefully. Unfortunately the vast majority of people out there believe the answer is to increase the maxRequestLength in web.config. How can that be considered a solution? It’s like saying the way to deal with traffic congestion is to double the size of every road. Someone, somewhere will then try and upload a file that is even bigger and the problem repeats itself.

I spent a long time looking for a solution and eventually came across a little trick which you can pull in your Global.asax:

  1. protected void Application_BeginRequest(Object sender, EventArgs e)
  2. {
  3.     int maxRequestLength = 4096000; // 4MB
  4.     if (Request.ContentLength > maxRequestLength)
  5.     {
  6.         HttpApplication app = sender as HttpApplication;
  7.         HttpContext context = app.Context;
  8.         HttpWorkerRequest wr = (HttpWorkerRequest)(context.GetType().GetProperty("WorkerRequest",
  9.             System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(context, null));
  10.         byte[] buffer;
  11.         if (wr.HasEntityBody())
  12.         {
  13.             int contentlen = Convert.ToInt32(wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
  14.             buffer = wr.GetPreloadedEntityBody();
  15.             int received = buffer.Length;
  16.             int totalrecv = received;
  17.             if (!wr.IsEntireEntityBodyIsPreloaded())
  18.             {
  19.                 buffer = new byte[65535];
  20.                 while (contentlen – totalrecv >= received)
  21.                 {
  22.                     received = wr.ReadEntityBody(buffer, buffer.Length);
  23.                     totalrecv += received;
  24.                 }
  25.                 received = wr.ReadEntityBody(buffer, contentlen – totalrecv);
  26.             }
  27.         }
  28.         context.Response.Redirect("~/Error.aspx/FileTooBig");
  29.     }
  30. }

Thanks to this guy for the hard work.

It seems to be about the only place in the code that you can do anything about the error. What it’s actually doing is reading in the whole of the request even though it is over your maximum request size. Once the whole request has been read you are able to make a response to the calling client, in this case a redirect to an error page. It’s possible that you could take this further and carry on with the page the user originally intended to work with, catching the error and displaying it there. But I’m too burned out to try that right now and this solution works fine for me!

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment