Using Protocol Relative URLs to Switch between HTTP and HTTPS

calendarFebruary 10, 2010 in HTTPS , HttpWatch , Internet Explorer

Attempting to use HTTP resources on an secure web page is a guaranteed way to annoy IE users, because it generates a confusing security warning for anyone running with the default IE settings. Our previous post on fixing this message in IE 8 is responsible for more than 50% of the traffic and comments on this blog. Hopefully, Microsoft will take note and change this in a future version of IE.

In the meantime, it’s important to avoid this warning by ensuring that every image, CSS and Javscript file on a secure page is accessed using HTTPS. For content on the same domain it’s quite straightforward – you just need to use relative URLs. A relative URL contains the ‘offset’ URL that needs to be applied to the page’s absolute URL in order to find a resource.

For example, here’s a screen shot from HttpWatch accessing our home page over HTTPS:

HttpWatch Home Page Access with HTTPS

Searching for one of the images in HttpWatch shows that it was specified with a relative URL and the switch to HTTPS happened automatically:

Relative URL

A problem arises though, if you attempt to access a resource from a different domain because you can’t use the simple path-relative URL to access the resource. This often happens when you attempt to use a third party service such as Google Analytics or a third party Ajax library CDN.

Google Analytics solves the problem with its external javascript file by recommending the use of this code to dynamically switch protocols:

var gaJsHost = (("https:" == document.location.protocol) ?
    "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
    "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

Another solution is to hard code the external resource with an HTTPS based URL regardless of how the containing page is accessed. This avoids any security warnings in IE, but does mean that the HTTPS resource download will consume more CPU resources in cases where the HTTP download would have been sufficient.

The solution we prefer to use is to specify a Protocol Relative URL. It’s just like a regular URL except that you leave out the protocol prefix. For example, when Microsoft recently announced SSL support for their Ajax CDN the recommended script tag for secure pages was:

<script src=”https://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js” type=”text/javascript”></script>

But if you change this to a protocol relative URL:

<script src=”//ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.jstype=”text/javascript”></script>

You get the automatic use of HTTPS on secure pages and avoid the overhead of HTTPS on non-secure pages.

We put together a simple jQuery demo page using this technique. In HttpWatch, you can see that the resource is automatically downloaded with HTTP for non-secure access:

and HTTPS with secure access:

One downside of this approach is that there will be separate cached copies for both the HTTP and HTTPS based URLs. If a vistor to your site first uses a non-secure HTTP based URL and then switches to HTTPS they would have to download fresh copies of resources that had already been accessed over HTTP.

UPDATE: Steve Souders pointed out another downside to using protocol relative URLs; they cause a double download of CSS files in IE 7 & 8.

23 thoughts on “Using Protocol Relative URLs to Switch between HTTP and HTTPS

  1. Aaron Peters says:

    Good article!

    You mention that “the downside of this approach is that there will be separate cached copies for both the HTTP and HTTPS based URLs. If a vistor to your site first uses a non-secure HTTP based URL and then switches to HTTPS they would have to download fresh copies of resources that had already been accessed over HTTP.”

    That’s not a downside of this *specific* approach, right?
    This downside also exists if you hard code the external resource with an HTTPS based URL.

    – Aaron

  2. Aaron,

    The advantage of hard coding an HTTPS based URL is that you will have already loaded the resource (e.g. javascript) in the HTTP part of the your site ready for use in the HTTPS part.

    Assuming that you cache everything except HTML (see http://blog.httpwatch.com/2007/12/10/two-simple-rules-for-http-caching/ ) the cached resource can be used in HTTPS part of your site with no network round trip.

    If you don’t hard code the URL then switching to the HTTPS part of your site causes the resource to be download loaded again; even though you have the HTTP acquired resource in the browser cache.

  3. Aaron Peters says:

    Are you suggesting to do this:

    on the non-secure page, load the JS file from a HTTPS URL. Like so: <script src=”https://www.domain.com/js/file.js”>

    I assume this is not what you mean.
    Which is why I did a test:

    I just visited the site of a large NL bank in The Netherlands (IE7, empty cache).
    http://www.snsbank.nl/particulier/home.html

    The file ‘home.css’ (http://www.snsbank.nl/static/snsbank/css/home.css) file is loaded into my browser cache. Cache-Control is set at 3600 (1 hour).

    Then I visit the same page on HTTPS:
    https://www.snsbank.nl/particulier/home.html

    The same CSS file ‘home.css’ is downloaded from the server (https://www.snsbank.nl/static/snsbank/css/home.css).

    Please point out what I don’t understand on this snowy winter day

  4. Yes, hard coding an HTTP URL would look like this:

    <script src=”https://www.domain.com/js/file.js” />

    BTW: a *protocol* relative URL would be like this:

    <script src=”//www.domain.com/js/file.js” />

    The NL bank example you give uses a *relative* URL to download the CSS file:

    <link type=”text/css” rel=”stylesheet” media=”screen, projection” href=”/static/snsbank/css/home.css” />

    Visiting the site with HTTP causes the browser to download and cache:

    http://www.snsbank.nl/static/snsbank/css/home.css

    When you then visit with HTTPS the relative URL in the HTML indicates that this CSS file is required:

    https://www.snsbank.nl/static/snsbank/css/home.css

    The browser doesn’t have this cached and must download a copy. It works like this because a site could deliver different versions of a file depending on whether HTTP or HTTPS was used.

    The NL site would benefit from hard coding the HTTPS URL if most customers who accessed the site would then login and access it through HTTPS.

  5. Careful. Using protocol relative URLs for stylesheets causes them to be downloaded twice in IE 7&8:

    http://www.stevesouders.com/blog/2010/02/10/5a-missing-schema-double-download/

  6. Jason Persampieri says:

    Are you kidding me? That is way too easy a solution. Fortunately Steve Souders has found one (albeit tiny) hiccup.

    http://www.stevesouders.com/blog/2010/02/10/5b-document-write-scripts-block-in-firefox/

    But still entirely worth it.

    Thanks!

  7. Morgan Cheng says:

    Steve Souders points out another downside of this trick. In IE7/IE8, the non-schema URL will make CSS resource to be downloaded twice.

    http://www.stevesouders.com/blog/2010/02/10/5a-missing-schema-double-download/

  8. Aaron Peters says:

    Ok, got it. Txs.

    The downside of hardcoding the HTTPS URL for the JS (or other files) is the extra time it takes for this file to download, since HTTPS is slower. So you really have to make a good decision on which files you do and don’t want to apply this ‘trick’ to.

  9. Steve,

    Thanks for highlighting the CSS double download problem.

  10. This is surely a TERRIBLE idea!

    HTTPS takes something like 4 times the resources from your server. There are also overheads on the client and the network.

    To say nothing of caching problems – e.g. the scripts may NOT be cached as many caches won’t take HTTPS which is correct as HTTPS is point-to-point encryption generally – e.g. server to CLIENT – so the cache CANNOT hold it. This may not be too much of an issue for random clients connecting to their ISP and using Google/MS CDN’s but it is certainly a massive problem on corporate networks with limited Internet bandwidth going through a proxy for security.

    So you should NEVER deliver over HTTPS unless you really need to (or really don’t care about resources end-to-end).

    IE can be configured to allow mixed content without a warning – this is best done for specific, trusted domains.

    Regards, Julian Knight.

  11. Thanks this helped a lot with some problems that I had.

  12. Amit says:

    This won’t work on Firefox 3.6 which i am using. IE 7/8 wrks fine.

    I had to hardcode http://domain for FF to work.

  13. Adrian says:

    Hi there. I have read all comments and no clue why on a secured website this security warning still appears? :| I have used HttpWatch and all requests are sent with https protocol. Could it be a cache problem?
    The application is developed in asp.net, uses jquery, datatables from jquery.
    The warning appears randomly.
    Any ideea how I could solve it?

  14. Have you looked through these posts and their comments:

    http://blog.httpwatch.com/2009/04/23/fixing-the-ie-8-warning-do-you-want-to-view-only-the-webpage-content-that-was-delivered-securely/

    http://blog.httpwatch.com/2009/09/17/even-more-problems-with-the-ie-8-mixed-content-warning/

    They are some javascript fragments that can cause a problem. Also, before checking in HttpWatch make sure you clear the cache, close all IE windows and test in a new session to make sure images in the in-memory image cache are not being accessed.

  15. Jon says:

    Can someone confirm that protocol-relative URLs work with url() references in CSS. E.g.

    test

    I have not had success with this in IE8 or FF3.6.

  16. Jon says:

    Here is an HTML-escaped version of my above example:

    <a style="background-image: url(//www.domain.com/bg.png);" href="http://www.domain.com">test</a&gt;

  17. Jon says:

    on second thought, it seems to work, at least for http.

Got Something to Say?

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Ready to get started? TRY FOR FREE Buy Now