IE6-8 unable to download file from HTTPS site

asp.net-mvc, https, internet-explorer, mime-types

Solution

I've come up with a workaround, but it's a definite hack - this is a new cache attribute to replace the built-in `[OutputCache]` one:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class IENoCacheAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsSecureConnection &&
            string.Equals(filterContext.HttpContext.Request.Browser.Browser, "IE", StringComparison.OrdinalIgnoreCase) &&
            filterContext.HttpContext.Request.Browser.MajorVersion < 9)
        {
            filterContext.HttpContext.Response.ClearHeaders();
            filterContext.HttpContext.Response.AddHeader("cache-control", "no-store, no-cache, must-revalidate");
        }
        else
        {
            filterContext.HttpContext.Response.Cache.SetNoStore();
            filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        }

        base.OnResultExecuting(filterContext);
    }
}

It's a workaround at best though - what I really want is to extend the existing `[OutputCache]` and `Response.Cache` structures so that they have the desired output suitable for legacy IEs.

Problem

I have an MVC .Net application that has actions that return report files, usually `.xslx`: ``` byte[] data = GetReport(); return File(data, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "filename.xlsx"); ``` This works great in testing and in all browsers, but when we put this on an SSL site it fails for IE6, 7 and 8 (all the proper browsers still work fine) with this unhelpful error: This used to work in a legacy application (non-MVC) that this action replaces. We can't tell our users to change anything locally - about 60% are still on IE6! How can I fix this using MVC? Update Further digging reveals that this is a fundamental failure in IE6-8. According to Eric Law's IE internals blog this happens because, during an SSL connection, IE treats the no-cache directive as an absolute rule. So, rather than not cache a copy, it considers no-cache to mean that it shouldn't be possible to save a copy to disk even when `Content-Disposition:attachment` and with an explicit prompt for a download location. Obviously this is wrong, but while it's fixed in IE9 we're still stuck with all the IE6-8 users. Using MVC's action filter attributes produces the following headers: ``` Cache-Control:no-cache, no-store, must-revalidate Pragma:no-cache ``` Using Fiddler to change these on the fly we can verify the headers that need to be returned instead: ``` Cache-Control:no-store, no-cache, must-revalidate ``` Note the order of the `Cache-Control` must have `no-store` before `no-cache` and that the `Pragma` directive must be removed entirely. This is a problem - we use MVC's action attributes extensively and I really don't want to rewrite them from scratch. Even if we could IIS throws an exception if you try to remove the `Pragma` directive. How do you make Microsoft's MVC and IIS return the no-cache directive that Microsoft's IE6-8 can handle under HTTPS? I do not want to allow private caching of the response (as per this similar question) or ignore the MVC built in methods with an override (as per my own answer, which is just my current best hack).

Original source

Related problems