Internet Explorer resets the connection after receiving an HTTP response from IIS

A problem was seen where Internet Explorer clients would reset the TCP connection between them and the IIS server when they received an HTTP 200 response for static content from IIS. The problem manifests itself to end users as slow performance of the web application they are browsing to. In a network trace, we could see that when the client was making its request, it was including the If-None-Match and If-Modified-Since headers in its request. It was doing this because the client (IE) had a version of the requested resource already in its client-side cache. By sending these headers, the client is essentially telling the web server to only send the resource back as a response IF the content is newer than that which is in the client side cache. The client's request looks like this:

1979 13:05:26.644 0009124D0802 001422241049 HTTP GET Request from Client

HTTP: GET Request from Client

    HTTP: Request Method =GET

    HTTP: Uniform Resource Identifier =/CDE/CDENameIFrame.htm

    HTTP: Protocol Version =HTTP/1.1

    HTTP: Accept = */*

    HTTP: Accept-Language =en-us

    HTTP: Accept-Encoding =gzip, deflate

    HTTP: If-Modified-Since =Mon, 28 Nov 2008 19:06:36 GMT

    HTTP: If-None-Match ="0467ada4ef4c51:0"

    HTTP: User-Agent =Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .

    HTTP: Host =iisserver

    HTTP: Connection =Keep-Alive

   

IIS receives the request and sends the following response:

1980 13:05:26.645 001422241049 CISCO 07AC87 HTTP Response to Client; HTTP/1.1; Status Code = 200 - OK

HTTP: Response to Client; HTTP/1.1; Status Code = 200 - OK

    HTTP: Protocol Version =HTTP/1.1

    HTTP: Status Code = OK

    HTTP: Reason =OK

    HTTP: Date =Tue, 09 Dec 2008 13:08:56 GMT

    HTTP: Server =Microsoft-IIS/6.0

    HTTP: X-Powered-By = ASP.NET

    HTTP: Content-Length =13521

    HTTP: ETag ="0467ada4ef4c51:0"

    HTTP: Last-Modified =Mon, 28 Nov 2008 19:06:36 GMT

    HTTP: Content-Type =text/html

    HTTP: Data: Number of data bytes remaining = 1234 (0x04D2)

Notice that in the response, IIS sends a Last-Modified date that matches the client's If-Modified-Since date, and an ETag value that matches the client's If-None-Match header value. Because these all match, Internet Explorer correctly assumes that the response status should be a 304-Not Modified. However as we see in this response, IIS is setting a 200-OK status. IE resets the connection because the 200 is invalid.

Why is IIS sending a 200 ok AND headers that indicate a not-modified scenario? Because htm is mapped to ssinc.dll:

ScriptMaps=".asa,C:\WINDOWS\system32\inetsrv\asp.dll,5,GET,HEAD,POST,TRACE

.asax,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG

.ascx,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG

.ashx,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,1,GET,HEAD,POST,DEBUG

.asmx,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,1,GET,HEAD,POST,DEBUG

.asp,C:\WINDOWS\system32\inetsrv\asp.dll,5,GET,HEAD,POST,TRACE

.aspx,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,1,GET,HEAD,POST,DEBUG

.axd,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,1,GET,HEAD,POST,DEBUG

.cdx,C:\WINDOWS\system32\inetsrv\asp.dll,5,GET,HEAD,POST,TRACE

.cer,C:\WINDOWS\system32\inetsrv\asp.dll,5,GET,HEAD,POST,TRACE

.config,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG

.cs,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG

.csproj,C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG

.htm,C:\WINDOWS\system32\inetsrv\ssinc.dll,5,GET,POST <-------------------------------------------------------<

.html,C:\WINDOWS\system32\inetsrv\ssinc.dll,5,GET,POST <-------------------------------------------------------<

What does mapping to ssinc.dll have to do with this? Ssinc.dll does not handle If-* headers the same way the static file handler does. This means that even if we SHOULD be sending a 304 response, based on the headers in the client's request, we WON'T as long as we're mapped to ssinc.dll.

WHY is htm mapped to ssinc.dll? Because the html pages make use of include files via the #include statement. Include files in .htm/.html files will not get processed unless .htm/.html is mapped to ssinc.dll, as per the following article:

Web Page Does Not Display Data from Include File

https://support.microsoft.com/default.aspx?scid=kb;EN-US;274150

So to summarize, IIS was configured to have ssinc.dll handle the htm/html requests, instead of the default static file handler. The IE clients expected to receive a 304-Not Modified response, but ssinc.dll was never designed to send 304 responses. Since IE believes the 200 response to be invalid, it resets the connection. This behavior of Internet Explorer is discussed in more detail in the following article:

You may experience poor Web performance when you use Internet Explorer 6 to try to access a Web application that is hosted on Internet Information Services 6.0

https://support.microsoft.com/default.aspx?scid=kb;EN-US;922703

There are a few options to work around this behavior:

1) Remove the scriptmap of htm to ssinc.dll, and move the include file code right into the htm pages themselves. This will allow the static file handler to process the requests, and send either a 200 or 304 response as appropriate.

2) Remove the scriptmap of htm to ssinc.dll, and instead map .htm to ASP.dll. This will allow for the include files to be processed, but does not allow for IIS to ever send a 304 since asp.dll will never set a 304 status. However, the client will never think it should be receiving a 304 response, will always accept the 200, and won't reset the connection.

3) Inhibit the client from caching the static content, so it won't ever expect to receive a 304- Not Modified response.

Comments