Content-Length and Transfer-Encoding Validation in the IE10 Download Manager

Back in March of 2011, I mentioned that we had encountered some sites and servers that were not sending proper Content-Length headers for their HTTP responses. As a result, we disabled our attempt to verify Content-Length for IE9.

Unfortunately, by April, we’d found that this accommodation had led to some confusing error experiences. Incomplete executable files were not recognized by SmartScreen’s Application Reputation feature, and other signed filetypes would show “xxxx was reported as unsafe” because WinVerifyTrust would report that the incomplete file’s signature was corrupt. This problem was very commonly reported for large files (e.g. 50mb installers) by users in locations with spotty network access (e.g. where such connections are often interrupted).

With IE10, we’ve reenabled the Content-Length / Transfer-Encoding checks in IE’s Download Manager. If the Download Manager encounters a transfer that does not include the number of bytes specified by the Content-Length header, or the transfer fails to end with the proper 0-sized chunk (when using Transfer-Encoding: chunked), the following message will be shown:

    IncompleteFile

If the user clicks Retry, IE will attempt to resume (or restart the download). In many cases of network interruption, this feature helps ensure that the user is able to download the complete file. As a compatibility accommodation, if the retried transfer again does not provide the expected number of bytes, Internet Explorer will permit the download to be treated as “finished” anyway, so that users are not blocked from interacting with buggy servers.

For instance, one buggy pattern we've seen is a server which delivers the HTTP response body as a single chunk, then calls HttpResponse.Close() instead of the proper HttpApplication.CompleteRequest.

  // Add Excel as content type and attachment
  Response.ContentType = "application/vnd.ms-excel";
  Response.AddHeader("Content-Disposition", "attachment; filename=" + binTarget);

  mStream.Position = 0;
  mStream.WriteTo(Response.OutputStream);
  Response.Flush();

  // BAD PATTERN: DO NOT USE. 
  // See https://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx
  Response.Close();                 

Calling Close() like this omits the final chunk, and would cause the server's output to fail in the Download Manager if not for the compatibility accommodation.

You can test how browsers handle incorrect transfer sizes using these two Meddler scripts:

 -Eric