Jesse Taber

if I call it a blog I'll feel bad when I don't update it every week
posts - 26, comments - 70, trackbacks - 0

My Links

News

Twitter












Tag Cloud

Archives

Image Galleries

‘Content-Length’ Header Replaced With ‘Transfer-Encoding: chunked’ in ASP .NET

About a week ago we received a support call from one of our customers asking why she couldn’t open PDF files on our website anymore. She was using Chrome and the browser tab would just hang with the ‘Loading’ animation and a gray background after requesting an invoice PDF. After a little digging we figured out that this hang-up was occurring while Chrome was opening the PDF document. We were easily able to reproduce this issue ourselves in the production environment, but only while using Chrome. We were not, however, able to reproduce it in any of our QA / test environments. All environments are running the same version of ASP .NET (3.5) and IIS (7.5).

After trying dozens of different combinations of browser settings, PDF file sizes, and IIS settings, I finally noticed that the content-length header that we set explicitly before writing the PDF file bytes out the response stream was being replaced with a ‘transfer-encoding: chunked’ header in our production environment (but not in any of our QA environments). In some circumstances Chrome chokes on file downloads using the transfer-encoding: chunked header. Initial research into the issue yielded a post reporting that ASP .NET will set the transfer-encoding: chunked header for you when calling ‘Flush’ manually without explicitly setting a content-length header. Unfortunately for me we were explicitly setting the content-length header, so it was back to the drawing board.

After banging my head against the wall for a few hours comparing the raw IIS configuration XML between our QA and production servers I finally remembered that we had seen some very odd response related issues that stemmed from an HTTP Response Filter we were using on some pages. Sure enough, the filter was the cause of our issues in this instance as well.

The reason we were only seeing this issue in the production environment was that we use an HTTP Module to profile page requests. One of the things we measure is the size of the ‘viewstate’ field that is sent down for each request to detect pages that might be viewstate abusers. In order to track the size of the viewstate data sent down we attach a stream to the ‘Filter’ property of the HttpResponse that intercepts and records the value of the viewstate hidden field. Disabling this viewstate tracking filter for the page that generates and sends PDF files down to the browser resolved the issue. This module was enabled in our production environment but nowhere else.

It seems unlikely that anyone else will ever stumble across this same issue, but if I can save someone else a few hours of troubleshooting time with this blog post then it’ll be well worth the short time it took me to write this up. In summary, the following circumstances lead to the replacement of the content-length header with a transfer-encoding: chunked header:

  • Site is hosted on IIS 7.5 (I never tested this on IIS 7, though I do know that the Visual Studio development web server does NOT exhibit the same issue)
  • A stream is set on the ‘Filter’ property of the HttpResponse. What the filter actually does seems immaterial. I was able to reproduce the problem with a filter that simply passed the raw bytes through without modifying them at all.
  • A content-length header is explicitly set.
  • ‘Flush’ is called on the HttpResponse directly after writing some or all of the file contents to the response. (in our application we were calling Flush multiple times sending down about 1kb of data at a time as our files can be quite large sometimes.)
  • (Optional) Calling ‘End’ on the HttpResponse after sending all of the file contents. (This is not explicitly required for seeing the transfer-encoding: chunked header, but this does seem to be a requisite for having Chrome choke on opening the PDF.

I created a quick and dirty web forms app to reproduce the issue that you can grab on GitHub. I was also able to deploy and reproduce the same issue using this sample app on AppHarbor:

Print | posted on Monday, January 02, 2012 7:58 PM |

Feedback

No comments posted yet.
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 

Powered by: