title: Why is ASP.NET replacing a Content-Length header with a Transfer-Encoding header when manually flushing a response?
body: <p>Our web application (ASP.NET Web Forms) has a page that will display a recently generated PDF file to users. Because the PDF file is sometimes quite large, we've implemented a "streaming" approach to send it down to the client browser in chunks.</p>
  
  <p>Despite sending the data down in chunks, we know the full size of the file prior to sending it, so we set the Content-Length header appropriately. This has been working in our production environment for awhile (and continues to work in our test environment with a virtually identical configuration) until today. The issue reported was that Chrome would attempt to open the PDF file but would hang with the "Loading" animation stuck.</p>
  
  <p>Because everything was still working fine in our test environment I was able to use Firebug to take a look at the response headers that were coming back in both environments. In the test environment, I was seeing a proper 'Content-Length' header, while in production that had been replaced with a <strong>Transfer-Encoding: chunked</strong> header. Chrome doesn't like this, hence the hang-up.</p>
  
  <p>I've read some articles and posts talking about how the Transfer-Encoding header can show up when no Content-Length header is provided, but we are specifying the Content-Length header and everything still appears to work while running the same code for the same PDF file on a test server.</p>
  
  <p>Both test and production servers are running IIS 7.5 and both have Dynamic and Static Compression enabled.</p>
  
  <p>Here is the code in question:</p>
  
  <pre><code>var fileInfo = new FileInfo(fileToSendDown);
  Response.ClearHeaders();
  Response.ContentType = "application/pdf";            
  Response.AddHeader("Content-Disposition", "filename=test.pdf");
  Response.AddHeader("Content-Length", fileInfo.Length.ToString());
  var buffer = new byte[1024];
  using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
  {
      int read;
      while ((read = fs.Read(buffer, 0, 1024)) &gt; 0)
      {
          if (!response.IsClientConnected) break;
          Response.OutputStream.Write(buffer, 0, read);
          Response.Flush();
      }
  }
  </code></pre>
  
  <p>I was fortunate to see the same behavior on my local workstation so using the debugger I have been able to see that the 'Transfer-Encoding: chunked' header is being set on the 2nd pass through the while loop during the call to 'Flush'. At that point, the response has both a Content-Length header and Transfer-Encoding header, but somehow by the time the response reaches the browser Firebug is only showing the Transfer-Encoding header.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I think I've tracked this down to using a combination of sending the data down in "chunks" AND attaching a 'Filter' to the HttpResponse object (we were using a filter to track the size of viewstate being sent down to each page). There's no sense in us using an HTTP filter when sending a PDF down to the browser, so clearing the filter here has resolved our issue. I decided to dig in a little deeper purely out of curiosity and have updated this question should anyone else ever stumble onto this problem in the future.</p>
  
  <p>I've got a simple app up on AppHarbor that reproduces the issue: <a href="http://transferencodingtest.apphb.com/" rel="noreferrer">http://transferencodingtest.apphb.com/</a>. If you check both the 'Use Filter?' and 'Send In Chunks?' boxes you should be able to see the 'transfer-encoding: chunked' header show up (using Chrome dev tools, Firebug, Fiddler, whatever). If either of the boxes are not checked, you'll get a proper content-length header. The underlying code is up on github so you can see what's going on behind the scenes:</p>
  
  <p><a href="https://github.com/appakz/TransferEncodingTest" rel="noreferrer">https://github.com/appakz/TransferEncodingTest</a></p>
  
  <p>Note that to repro locally you'd need to setup a local website in IIS 7.5 (7 may also work, I haven't tried). The ASP .NET development server that ships with Visual Studio DOES NOT repro the issue.</p>
  
  <p>I've added some more details to a blog post here: <a href="http://gruffcode.com/2012/01/02/content-length-header-replaced-with-transfer-encoding-chunked-in-asp-net/" rel="noreferrer">'Content-Length' Header Replaced With 'Transfer-Encoding: Chunked' in ASP .NET</a></p>