When building a web site with HTTPS pages, one of the annoying tasks is to ensure that those pages make no references to HTTP resources. If they do, then Internet Explorer will pop up alarming messages about mixing secure and insecure content, and do you want to display the insecure content. This confuses users and generally discourages them from continuing to use your site.

To fix the problem, all URLs on the page must use HTTPS. Web sites these days are built from reusable components, some of which may be used on both HTTP and HTTPS pages. How to make the URLs correct for both?

Relative URLs are the answer. Typically, relative URLs omit the hostname, specifying the full path to the resource, or perhaps just a single path component:

<img src='/pix/smiley.jpg' />
<img src='smiley.jpg' />

Either of these images will display without warning on either HTTP or HTTPS pages. Since the host name is omitted, it uses the host name from the page being displayed. But these URLs also omit the protocol scheme, so the protocol is taken from the base URL also. On an HTTP page, the images will be requested using HTTP, on an HTPPS page, they will use HTTPS. That's why there's no warning, because there's no mixing of secure and insecure content.

But what if you need to pull resources from another site? For example, a CDN (content delivery network)? Here the problem seems to be thornier:

<img src='http://fast.cdn.net/pix/smiley.jpg' />

If this reference appears in an HTTPS page, the mixed content warning will appear. How to craft a reference that works for both? The answer is again relative URLs, but using a more obscure syntax:

<img src='//fast.cdn.net/pix/smiley.jpg' />

Here, we've left off the protocol scheme, but included a host name. In this case, the protocol scheme from the displayed page will be used, but against the host in the URL. The relative URL system is still in play here: omitted portions of the URL at the beginning are taken from the base page, and the relative URL takes over whereever it starts. On an HTTPS page, this will be an HTTPS request to the CDN, on an HTTP page, it will be an HTTP request.

You have to be careful to only use this syntax in pages destined for browsers. If you put it in an email, there will be no base page URL to use in resolving the relative URL. In Outlook at least, this URL will be interpreted as a Windows network file, not what you intended.

BTW: when trying to get rid of the mixed secure and insecure content warning, you really have to fix up every URL, even if it doesn't seem like it's being used for anything. Flash content? There's a macromedia.com URL in there in the codebase attribute:

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
   width="600" height="400"> ... </object>

Making it scheme-relative as shown will also prevent warnings.

tagged: , » 40 reactions


Mark Mascolino 12:18 AM on 18 Oct 2007

Wow, you do learn something every day. I didn't realize that the full url minus the protocol was valid syntax. Interesting.

Jerald 8:38 AM on 18 Oct 2007

Thanks! That's damn nice.

BTW, do you know in which HTML version did this appear?

mikey 10:25 AM on 18 Oct 2007

Amazing. I have never seen that syntax before.

Also, Google Analytics provides a secure reference to their .js file as well.

Roberto 10:41 AM on 18 Oct 2007

Great ! Thanks very much.

Braden Anderson 11:21 AM on 18 Oct 2007

Very clever. Thanks. Also, your previous two posts are fantastic. Here's one more subscriber to your RSS feed.

steve minutillo 11:43 AM on 18 Oct 2007

Which browsers does this work in?

dave g 12:08 PM on 18 Oct 2007

I had no idea about this, though it doesn't work for me...
Would love to see it working. Do you have it running somewhere?

Ned Batchelder 1:31 PM on 18 Oct 2007

I don't know in which version of HTML it appeared. The HTML 2 spec references RFC 1808 which describes this behavior, and was written in 1995.

I know this syntax works in IE6, IE7, FF2, and Safari 2 and 3. I don't know of any browsers in which it doesn't work.

I think this is not a case of new syntax, but of a specialized and little-used syntax.

Ned Batchelder 1:32 PM on 18 Oct 2007

dave g: URLs like this are on tabblo.com now. Load the home page and look at the source....

engtech 1:53 AM on 19 Oct 2007

The big downside with relative urls in blog posts is that they never get translated in the outgoing RSS feed.

complete pain in the butt.

Craig 5:44 AM on 19 Oct 2007

Wow - I never realised that. Another snippet for the HTML box of tricks!

Shantanu Oak 3:32 AM on 20 Oct 2007

I wish most of the web developers who use https should read this post.
@engtech : The contents of the secure pages are hardly pushed into the RSS feeds anyway. So I don't think that's a big downside.

Dave 5:11 AM on 22 Oct 2007

Very interesting. Could also be used to shirk page file sizes by a few bytes, even on normal HTTP sites.

Dave 5:11 AM on 22 Oct 2007

Oops, shrink, not shirk.

zen 2:51 AM on 24 Oct 2007

I had no luck with this technique - IIS server refused to serve up the image when referenced this way - main environment was HTTPS, image was on HTTP server.
Does this assume a certain default server or browser setting?

Ned Batchelder 7:41 AM on 24 Oct 2007

The server settings have nothing to do with it: the resolution of a relative URL into a server request is all done at the browser.

If you install Fiddler, you'll be able to see the requests the browser is making. That should help find the problem.

David Weingart 12:35 PM on 24 Oct 2007

Ok, I've been building websites since 1996, and I had absolutely no idea about this. I guess you do learn something new every day. :-)

Chet 9:02 AM on 28 Nov 2007

Awesome. I swear I had Saved As New this post in my Bloglines account... but which RSS feed was it? To paraphrase Michael Corleone, "Ned, I knew it was you." Found it, used it, great tip.

Yoav Shapira 1:48 PM on 12 Aug 2008

Ned, that's a great tip. I'm going to try using it right now. Thanks for publishing it in a concise, clear form.

Pas B 3:44 PM on 10 Aug 2009

So, this represents your (the user's) agreement to also trust the linked third party? How do browsers display this additional trust / certificate?

Pas B 3:47 PM on 10 Aug 2009

Just to clarify, even if the certificate is authenticated, it is STILL bringing the third party into the communication.

Jacob Rothstein 4:01 PM on 10 Aug 2009

Fantastic find! Thanks for the tip.

Sine Language 12:03 AM on 11 Aug 2009

It's 2009 people. All of the content you put in front of the Customer should be done in something like ExtJS.com, GWT or a finite number of other JavaScript-targeting frameworks that have dedicated, if not massive, teams behind them. That means the only "httpS" you'll ever need to worry about is in the base-URL for your back-end server's AJAX responder.

Ben XO 6:19 AM on 11 Aug 2009

Pas B,

The point of the "mixed secure and insecure content" warning is that the browser should not show the padlock icon - symbolic of "this content was encrypted" - on a page where some of the content on the page was not encrypted.

Browsers will not usually expose the certificate information of the certificates on 3rd party sites loaded into the page unless they are invalid.

The "trust" implied here only goes as deep as validation of identity - it's assumed that if every certificate is valid and signed by a root authority, then you can trust the content to be authentic.

Ned Batchelder 6:45 AM on 11 Aug 2009

Actually, the point is to automatically manage the page so that if the HTML is served over https, then the rest of the content is also, and if the HTML is not served over https, then none of the content is.

The browser warnings happen when you mix the protocols, and this post shows a simple solution for avoiding the mixing.

Asim 4:43 AM on 13 Jan 2010

What about links, when i am using https://www,doamin.com/securepage.asp to browse page then all non secure links appears secure meaning if I want to go back to my non-secure page from a secure page then URL shows me https

Ned Batchelder 7:06 AM on 13 Jan 2010

If you have a page served by https, and you want the links from it to use http, then you have to provide the http: scheme in the URL. Leaving it out will default the scheme to https.

Klortho 4:00 PM on 14 Apr 2010

This depends on the server that you're linking to understanding https. Not all servers do. This may be why some of the people above had trouble getting it to work. If you have <img src='//my.home.server/img.jpg'/> on a page, it will look fine in http, but the image won't show up in https.

Matt 1:10 PM on 4 May 2010

Sine Language,
Not everything is a web application. Some of us develop sites that we like Google to be able to index, so grabbing all of the context via ajax is not a viable solution.

That's a good point. You want to make sure the server supports https before using this technique.

Efren 12:42 AM on 14 Feb 2011

Will these urls be indexed properly by Google?

Phani 1:52 AM on 31 Oct 2011

Great solution. It worked for me.


drpciv 11:05 AM on 16 Jul 2013

Leaving it out will default the scheme to https.

Ned Batchelder 1:45 PM on 16 Jul 2013

@drpciv: no, leaving out the scheme will default it to the scheme the current page is served with. On an http page, it defaults to http. On an https page, it defaults to https.

stefan 1:12 PM on 19 Nov 2013

Thanks for writing this article just got me out of tight spot!

I first saw this technique used in the markup of the html5 boilerplate to load jQuery in either http or https environments, this of course came years after this post was written.

stefan 9:43 AM on 20 Nov 2013

Just out of interest does this have any performance issues?

Ned Batchelder 11:13 AM on 20 Nov 2013

@Stefan, I haven't measured it, but there's no reason to think there's any performance impact from this. This works for the same reason that the page "http://example.com/a.html" with a link to "b.html" will find b.html on example.com. It's simple string manipulation as part of making a relative URL absolute.

stefan 3:50 PM on 21 Nov 2013

I have discovered this doesn't work with CSS files in IE7 possibly IE8 as the browser will download the images twice which is a performance hit.


George 5:14 AM on 17 Oct 2014

Thanks for the article, Ned. Learnt something new

Zerocode 4:24 AM on 5 Nov 2014

very nice article. solved my problem. I was using a company header image in html email body where our QA environments run on http and production environment run on https. So I was confused how I am gonna add the image url. So i just skipped the protocol part and used the relative url as //abc.pqr.in/_layouts/images/header.jpg.
And its working fine.

Claude Corry 7:09 AM on 29 Feb 2016

My sites are all wordpress so is there a certain file you need to do this in or is there a plugin that will do this job?

Add a comment:

Ignore this:
not displayed and no spam.
Leave this empty:
not searched.
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.