HttpControllerHandler.ConvertResponse prevents manual writing of Pragma header

Topics: ASP.NET Web API
Jul 26, 2012 at 9:31 AM
Edited Sep 12, 2012 at 2:08 PM

I've converted this to an issue (http://aspnetwebstack.codeplex.com/workitem/410) as I think it's better suited as one. 


 

With the logic currently in this method it's impossible to write to the Pragma response header unless you also set the CacheControl header.

Here's a question on StackOverflow, which also links to a related question on Programmers which describes why I might want to use the Pragma header.

E.g:

Response.Headers.Add("pragma", some_value);

Will not work, because of the following code in ConvertResponse:

CacheControlHeader cacheControl = response.Headers.CacheControl;
// TODO 335085: Consider this when coming up with our caching story
if (cacheControl == null)
{
    // DevDiv2 #332323. ASP.NET by default always emits a cache-control: private header.
    // However, we don't want requests to be cached by default.
    // If nobody set an explicit CacheControl then explicitly set to no-cache to override the
    // default behavior. This will cause the following response headers to be emitted:
    //     Cache-Control: no-cache
    //     Pragma: no-cache
    //     Expires: -1
    httpContextBase.Response.Cache.SetCacheability(HttpCacheability.NoCache);
}

The comments do speak for themselves; although I think that this should not rely on Asp.Net's handling of the HttpCacheability.NoCache directive, as that writes the three headers mentioned with impunity.  Thus, if a Pragma (in particular), has been added upstream it will get wiped.  In a platform like the Web API, the upstream code should have full and 'natural' control of the web responses that are sent.

Currently the solution to this is to manually add a CacheControlHeader to the HttpResponseMessage:

Response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue()
{
  NoCache = true
};
toLog.Response.Headers.Add("pragma", some_value);

Which, as we see from the above code then disables the if statement.  I'm not entirely sure that this on its own, however, is enough actually disable caching in all cases, I think we do need Expires also.

The Pragma header in this case isn't just intended for the no-cache value, it can also be used to carry application-specific values that, crucially, should not be stripped by downstream proxies, and which makes it a good choice for sending things like unique request IDs - which is what I intended to use it for.