Posts Tagged IE8

Domain-Sharding and SSL

Hi there!

Some time ago I noticed some weird behaviour on our website so I thought it would be a good idea to revisit this issue. Part of the above mentioned website is a selfcare area, where our customers are able to view their bill, to change the product options etc. etc. This area requires a login and so the login itself, as well as the subsequent pages are secured by SSL.

SSL and Performance Optimization was for quite some time a very difficult beast to debug, but fortunately with Pat Meenans WebPageTest this was solved at least for IE. In the old days you could use HTTPWatch for example, to see the HTTP interaction within the SSL tunnel, but you were unable to view the TCP Connection flows. With Microsofts Visual Roundtrip Analyzer you were able to see the TCP Connection flows, but you were unable to see the HTTP Conversation within the SSL Tunnel. Pat’s tool was the first (maybe still is the only one) that allowed to see both, the TCP Connection flow as well as what happens within the SSL Tunnel.

So, back to our page. In one of our former optimization iterations we decided to do some domain sharding. With this we wanted to improve performance especially for IE6 and IE7 users, as these Browsers only open up 2 TCP Connections per domain. Resulting in a performance limit, that is often lower than what your bandwidth is able to provide.

We implemented that in a way, that we could follow another performance rule, which is “Make static content cookie-free”. So we set up another Domain,, which we used for the above mentioned domain sharding, as well as keeping most of the content cookie-free.

There are some reasonable concerns regarding domain sharding in conjunction with SSL, as you not only have an additional DNS lookup and TCP handshake, but also an additional SSL handshake, which can be quite time-consuming. But we were pretty confident, as our customers are solely based in small Germany with a RTT of ~50 ms, that the benefit of 4 connections would outweigh the impact of that additional DNS lookup and TCP/SSL Handshake.

So, when I did a run with, the result in IE7 looked like this:

Hmm… that was weird… As you can see, you have some 2 connection waterfall behaviour, but for the first 7 objects, it seems like the TCP / SSL handshake is closed after each object, and re-established for the next one. Now THAT is much more painful, than what we would have expected…

So I was almost picking up the phone to call the Webserver Admin, that probably the Connection: Keep-alive Headers were not set correctly in Apache, but I decided first to check the HTTP Headers. And they looked like this:

Request Headers:

GET /selfcare/content/staticcode/tls/kundencenter/1025300/2010-06-23-09-49-15/ui.all.css HTTP/1.1
Accept: */*
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; PTST 2.257)
Connection: Keep-Alive

Response Headers:

HTTP/1.1 200 OK
Date: Thu, 13 Jan 2011 07:46:20 GMT
Server: Apache
Expires: Fri, 14 Jan 2011 07:45:33 GMT
Cache-Control: public, max-age=3628800
Content-Language: de-DE
Vary: Accept-Encoding
Content-Encoding: gzip
Age: 47
Content-Length: 5122
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/css;charset=UTF-8

As you can see, BOTH ends have a “Connection: Keep-Alive Header” using HTTP1.1. So why in the hell was the connection closed???

So I fired up Wireshark to look at the raw packet flow. Wireshark normally does not allow me to see the content within the SSL Tunnel, but in this case it didn’t matter, as I only wanted to see, WHO is closing the connection.

So it was ME (Or my machine) which was closing the connection, not the Server. As you can see in the trace, I am the one sending the TCP FIN.

So far, so bad.

Thinking about a solution / workaround I was wondering: Only the CSS files are affected. The Headers are correct and the same as the other assets, which are downloaded later on from the same domain. And with these assets I see a perfect persistent connection… Maybe it simply is due to being hosted on another domain?

Setting up another test page I dropped the idea of domain sharding, and used just one domain. The domain, where the base page resides. And the result was:

And the issue is gone… Meanwhile the Time-to-Render has improved from 2.2 to 1.6.

As it seems, the buggy TCP Connection behaviour seems to show up, when you are delivering CSS files VIA SSL from a different domain, than the base page.

I did a further test (waterfall coming soon), where I have shifted only the CSS files back to the domain, where the basepage resides. Result is

As you can see, the connection was kept-alive during the CSS downloads. BUT, later on, when the CSS-Images were downloaded from the sharded domain, suddenly these CSS-Images showed the Connection: Close behaviour!

Now, which IE Versions are affected? IE 7, as you can see above. IE 6 as well, IE 8 and IE 9 are not also affected. (Though I have to check with IE 8 and IE 9, if the issue would only be visible, if I add a seventh CSS file in the HEAD. But then you have another issue anyway). With IE 8 and IE 9, though, the issue is a lot less impacting, as you will be hit ONLY if you have more than 6 Stylesheets referenced in HEAD. Something which you should avoid anyway.

Firefox is not affected.

Finally: Who should care (If my observations/assumptions are true. Feel free to comment)?

– If it is not SSL, you have no problem.

– If you have inlined CSS, you have no problem.

– If your CSS files and CSS Images are on the same domain as the base page, you have no problem.

– If you have just a single CSS file via SSL in the HEAD, it is cacheable and your customers have a rather low latency, you shouldn’t worry too much.

– BUT, if you have multiple CSS files, or different CSS files on each page, which are on a different domain, then it might be an issue. More so, if they are not cacheable, and even more so, when your customers DO have high latency. Remember, NO RENDERING, until all CSS files from the HEAD are received! Blank Page!

So, even though there seem to be quite a lot of  conditions that have to be met, my assumption is that quite a few pages might be hit by this issue. I coincidentally saw that on Gateway’s site for example (CSS Images via SSL on a sharded Domain. Look at the bottom of the waterfall and the corresponding HTTP Headers). And it sounds reasonable. When you follow some of the performance best practices (Domain sharding, Make static assets cookie-free, Use a CDN) and are using SSL, you probably run automatically in this scenario.

Finally a big thank you to Thomas G., Daniel G. and Michael S. who supported me in this analysis!




I got in contact with Microsofts IE Team via their blog and indeed, they confirmed the above mentioned behaviour. So this is not a unique fail case with our domain, but actually a bug in IE, present in versions 6 to 9. In the same response they said they are looking to fix this in an upcoming IE version.

See the last 2 comments:

Comments (2)

IE 6 slowing down IE 8

Hi there!

As most of you know, performance improvement is an ongoing effort. Pages change, new stuff arrives, and your once so fast and optimized page becomes slower and slower… So it is good, to check your page regularly. Which I did with our site

When doing this, with the great help of, I stumbled across some interesting behaviour with IE 8. So let’s see, what we got here. The beginning of the page loads like this in a waterfall chart:

What caught my suspicion was the strange “gap” between combobox.css and errorboxes.css.css (sic!).

What is happening there? IE8, by default using 6 connections in parallel with HTTP1.1, is simply waiting ~0,15 seconds apparantly doing nothing. And then re-using its connections, to fetch two further CSS files. What happens here?

So I looked at the source of the page, and this is what I found right between these two objects:

<!–[if IE 6]> <link rel=”stylesheet” type=”text/css” href=””/&gt; <![endif]–>

Hmmm… Weird. This is an CSS file, that only IE 6 should load, to fix some CSS issues with that Browser. IE 8 should not be affected by this at all, and the Waterfall indeed showed, that the asset is not downloaded. Well, let’s try and see what happens, if I remove this comment from the source code.

Voila! The “gap” is gone. And IE 8 fetches all the CSS files at once, using all 6 connections in parallel. So we found the culprit.

Unfortunately simply removing this is not an option, as obviously somebody wanted on purpose a backwards compatibility to IE 6. And I was curious, if it could be fixed, by simply doing some re-sorting.  So my first try was to place this piece of code right BEHIND the regular CSS files. And the result was this:

Hm, unfortunately not really a leap forward. We simply have moved the “gap” from within the CSS files now to a position behind the files, right in front of JS files.

Other try. Let’s put it first! And the result is:

Wow, this comes a suprise. The “gap” is gone! I was pretty glad with that result, up until one of our Web Designers told me, that even though this looks pretty nice, I probably would break the functionality by doing so. Because IE 6 would load its CSS fixes, and when afterwards loading the default CSS objects, would overwrite its own fixes. We have to check on that.

So maybe it would be better, to deliver IE6 its own page by varying by User-Agent or whatsoever.  But the lesson I learnt now: Using the current mechanism for IE 6 surprisingly puts quite some penalty on IE 8. If possible, avoid this approach.

With a time to render of 1 second that our page has, this effect is responsible for 15% of that.

In case somebody knows a best practice, that doesn’t come with penalties, please feel free to comment.


Seems there is indeed a best practice, that solves the issue, without breaking functionality. And is easy. A small snippet of code solves the issue, placed in the HEAD before any CSS/JS Files being loaded. It looks like this:

<meta http-equiv=”X-UA-Compatible” content=”IE=edge” />

Meanwhile our page has changed a bit, concatenating most of the CSS files. So let me show you just briefly the Waterfall BEFORE adding this code:

And now AFTER this code has been added to the HEAD in front of loading the CSS Files:

Done! 🙂

Update 2:

Thanks to Stoyan, who found a serious flaw with my solution, which you can see in the comments below.

So I was going back to one of my initial ideas, putting the conditional comment in front of ALL CSS-Files. But this time, I left it empty. And had a second one, were it was originally placed, right between the two CSS-Files, which would be used as intended, to download the file.

What can I say, now it works, and IE 6 still gets its CSS File.

So the correct, stupid, solution is, to place this code before any CSS/JS gets loaded:

<!–[if IE]><![endif]–>

Visible here:

Sometimes reality bites… The first solution was from an analytical point much more convincing. 🙂 Now I do have an workaround, but with the much more unsatisfying feeling left, to not really understanding, why it works.

Thanks to Stoyan for finding this serious flaw!

Update 3:

I have seen in some boards recently a lot of comments like “Well, 0.15 seconds… So what. I won’t fix this just for a tenth of a second.” Be carefully: The delay depends on your specific site! Or, to be more precise: The transfer time of the CSS, that is loaded directly BEFORE the Conditional Comment.

Here is another case from, where the delay is almost half a second (!), instead of a tenth of a second:

With a time to render of 1.2 seconds, this is a good third  of it!

So you should test your sites behaviour, before deciding not to tackle this issue.


Comments (29)