Intermittently the Server sends back 0 byte WebResource.axd and ScriptResource.axd files

Recently had this problem with a customer.  The full details and the solution follow.

Problem

The customer had an AJAX website where intermittently he sees that the webresource.axd and scriptresource.axd come down from the server as 0 bytes and therefore the page is incorrect. When the issue happens, it keeps happening until the customer does an IIS reset or reloads the AppDoman by making some changes in the web.config.

The customer can repro the issue faster if he has HTTP Compression turned on but the issue happens even without compression. In the Fiddler, netmon or FREB tracing, we see that the server sends a HTTP 200 OK response and only the response headers with no body.

Cause

There are a few things at work here.  First there is a known bug in IE8 that is part of the problem.  We have known the IE8 could send corrupted requests to the server. These bad requests will cause runtime exceptions thrown by the corresponding handlers. The customer has implemented Application_Error method in global.asax to handle these errors by calling Server.Transfer to show a common custom error page (“~/HandleExceptions.aspx”) to end users. However, another exception was thrown from this error handling page. Here is the exception and stack from one of the dumps below.

 0:004> !pe 000000017f936130
Exception object: 000000017f936130
Exception type: System.Web.HttpRequestValidationException
Message: A potentially dangerous Request.RawUrl value was detected from the client (="...case();});</script><div%20id=%...").
InnerException: <none>
StackTrace (generated):
    SP               IP               Function
    00000000063FE030 000007FF0054698F system_web!System.Web.HttpRequest.ValidateString(System.String, System.String, System.String)+0x18f
    00000000063FE090 000007FF0055F969 system_web!System.Web.HttpRequest.get_RawUrl()+0xb9
    00000000063FE0D0 000007FF00316F99 mysite_web!MySite.Web.Code.Page.OnPreRender(System.EventArgs)+0x59
    00000000063FE120 000007FF0055F734 system_web!System.Web.UI.Control.PreRenderRecursiveInternal()+0x94
    00000000063FE170 000007FF0054571B system_web!System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)+0x13db
    00000000063FE240 000007FF00543467 system_web!System.Web.UI.Page.ProcessRequest(Boolean, Boolean)+0x187
    00000000063FE2A0 000007FF0054324C system_web!System.Web.UI.Page.ProcessRequest()+0x5c
    00000000063FE300 000007FF00401DA0 system_web!System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)+0xf0
    00000000063FE350 000007FF007BFA3A app_web_ohaik_5b!ASP.handleexceptions_aspx.ProcessRequest(System.Web.HttpContext)+0xa

The exception was thrown because the original url contains some javascript, which is not a “safe” string in ASP.NET perspective. Normally, the Server.Transfer will end the response for any further processing if no errors, but this exception interrupted the execution of Server.Transfer, which skipped the call to Response.End() and makes the server continue to process upcoming notifications/events. Even more unfortunately, the customer’s error handling page has an OutputCache directive, which makes the request respond to the UpdateRequestCache notification and put the half-way done response produced by the error handling page into the output cache for keys like WebResource.axd and ScriptResource.axd. Once these bad cache entries are put into output cache, the server cannot correctly respond for any new requests to WebResource.axd or ScriptResource.axd even with correct parameters.

Resolution

There are a few recommendations to resolve this issue:

  • The customer should remove the OutputCache directive from the HandleExceptions.aspx page. I can see the customer want the error page cached instead of rendering it every time. However, since this page is invoked by Server.Transfer, which calls Response.End anyway. So this page will never be cached if everything works fine. Only when something went wrong, the call to Response.End would be skipped and the bad response would be put into cache.
  • The above HttpRequestValidationException was thrown because url validation is on by default. The customer could add ValidateRequest=”false” in the Page directive of the HandleExceptions.aspx page. This will make the error page show correctly for these corrupted *.axd requests.