Internet Explorer cannot download over https

Hello World,

My favorite browser IE (pun intended) was at it again – driving me crazy with a weird message whenever someone tried to click a link on my page that should ordinarily present a file download dialog. This is how the scary as hell dialog looked like:

DownloadFail

“Internet Explorer cannot download from xyz. Internet Explorer was not able to open this internet site. The requested site may be unavailable or cannot be found”

The Problem

What the heck I said! Now the same link works perfectly if exposed via HTTP instead of HTTPS. So what did I do? Prayed to Google the savior and my prayers were heard in the form of this blog post by Eric Law [Ex MSFT]

As Eric explains, this dialog can be caused by any response headers that prevent caching. This includes Cache-Control and Pragma headers specifically. Although Pragma headers have been discontinued in the latest HTTP standards, older versions of IE (anything below 10 is old 🙂 ) interpret Pragma: no-cache similar to Cache-Control: no-cache. In addition if someone has the option “Do not save encrypted pages to disk” checked, they can also face issue downloading files from an SSL site. This option is found under Tools -> Internet Options -> Advanced and looks like this;

Capture

The Solution

Case 1: You are facing the issue on your system and have no control over the website from which the said no-cache headers are being sent

If you are the lucky one as described above, Microsoft prescribes the following registry settings to override IE’s behavior:

For the logged in user: the registry location HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings add the key “BypassSSLNoCacheCheck“=Dword:00000001

For all users: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings add the key “BypassSSLNoCacheCheck“=Dword:00000001

For details, refer to this link on MS Knowledge base

Case 2: You are the super developer of the website

If your the guy who created or maintains the site – today is your lucky day! What needs to be done is that we need to hack the HTTP response and strip off the Cache-control and Pragma headers and then add the header that will get rid of the issue. Here’s how

Step 1: Create an HttpModule

in your web solution, click add -> New class

For this class to be an Http Module, it must derive from IHttpModule:

 public class MyHeaderStrippingModule : IHttpModule, IDisposable

Now an Http module offers various events that let you tap into the pipeline at various processing stages. If you look up the documentation for IHttpModule, the event PreSendRequestHeaders looks promising. This is where we’ll add the code to strip off those headers. Following is the code for the complete module. I will elaborate the details in a moment:

public class MyHeaderStrippingModule : IHttpModule, IDisposable
{
/// <summary> The headers to cloak from the response </summary>
private static readonly List<string> HeadersToCloak = new List<string>
{
   "Cache-Control",
   "Pragma",
};

/// <summary> The HTTP application </summary>
private HttpApplication _httpApplication;

/// <summary> Initializes a module and prepares it to handle requests. </summary>
public void Init(HttpApplication context)
{
_httpApplication = context;

context.PreSendRequestHeaders += OnPreSendRequestHeaders;
}

/// <summary> Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule" />. </summary>
public void Dispose()
{
if (null != _httpApplication)
{
  _httpApplication.Dispose();
}
}

/// <summary> Called when the pre send request headers event occurs. </summary>
private void OnPreSendRequestHeaders(object sender, EventArgs e)
 {
    if (null == _httpApplication)
    {
     return;
    }    if (_httpApplication.Context != null)
    {
      var response = _httpApplication.Response;
      HeadersToCloak.ForEach(header => response.Headers.Remove(header));
      response.Headers.Add("Cache-Control", "private");
    }
 }
}

NOTE: I’m sure you can come up with a decent name for your module 🙂

This is what we are trying to do:

  1. We declare a readonly list that contains the headers to remove from the returned response
  2. In the intialization method (Init) we subscribe to the PreSendRequestHeaders event by attaching the OnPreSendRequestHeaders event handler
  3. In the event handler, we iterate over the Response.Headers collection and remove each header that is present in the list declared at the top

Step 2: Register the module

Now for IIS to honour this module of yours, you’ll have to tell it via entries in web.config. For pre IIS 7, this is the system.web section. For IIS 7 and above the configuration is to be under the system.webserver section:

 <system.webServer>

<modules runAllManagedModulesForAllRequests="true">

<remove name="MyHeaderStrippingModule"/>

<add name="MyHeaderStrippingModule" type="<namespace>.MyHeaderStrippingModule"/>
 </modules>

</system.webServer>

Note that the type attribute should specify the fully qualified name of where the class we’ve created resides. E.g. if the type resides under namespace MyCompany.Product.Http then type should say “MyCompany.Product.Http.MyHeaderStrippingModule”. If IIS cannot locate your module in the assembly you specify, you would get the beautiful YSOD (Yellow Screen Of Death) saying that it cannot load the module.

Once you have this setup, revisit the download link and it should present you with the download dialog as expected.

Happy Coding!

Advertisements
Tagged with: , , ,
Posted in .NET, ASP.NET
One comment on “Internet Explorer cannot download over https
  1. […] or via IIS Http headers settings. For details on how a custom Http module may do this, refer to my previous post where I show how one may tweak HTTP headers using the PreSendRequestHeaders event. For IIS […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

  • Comic for March 28, 2017
    Dilbert readers - Please visit Dilbert.com to read this feature. Due to changes with our feeds, we are now making this RSS feed a link to Dilbert.com.
%d bloggers like this: