IFrames, A TARDIS, and the Multiverse

TARDIS

Exploring iframes through a whovian’s eyes.

Over the past couple of years I have been working on a third-party JavaScript (3pjs) framework. I have come to know and love the iFrame element! Before working in the 3pjs world, I never appreciated the power and isolation that iFrames provide. I use to think of them as just an easy way to include content from another web page.

You may be asking yourself, “what do you mean third-party JavaScript (3pjs)”? When I say 3pjs I am talking about authoring a JavaScript application which will be included on pages you have no control over. Services such as disqus and olark are popular examples of 3pjs applications. When authoring an application that will be included and expected to run in a wide range of web pages it presents unique challenges. If you have ever written a script which must run in a range of browsers you are already familiar with compatibility challenges. 3pjs takes this challenge to the next level!

In the following series of posts I am going to describe how a 3pjs developer can defend against some of the common problems he’ll encounter when writing 3pjs. I will provide real world examples of problems I have run into while developing the 3pjs framework used by swoop. So lets get started!

WARNING: the posts that follow will include many references to Doctor Who. If you are not familiar with the series you should still be able to get the gist of what is being explained, but this series posts will be much more entertaining for those of us who enjoy watching the series.

Lets imagine that we want to create a script which records the current time on a web page. Getting the local time isn’t a very interesting script. A simple example like this will help illustrate some of the problems a 3pjs developer might face. Since the script will record the time we will call it Timelord. A simple example of the timelord script may look something like this.

var timelord = {
  setTime: function(ts) {
    timelordTech.send(ts);
  }
};

The details of the example are not important. We assume that the timelordTech object has a send utility for recoding a timestamp. Now we want to record the current time on every web page across the internet that will embed our script tag. Lets follow our timelord script on a little adventure across the web.

The web is like a Multiverse.

To the eyes of the Timelord (a 3pjs script) the web is like a multiverse. Web sites are like their own little universes, from the script’s perspective all look relatively equal. But they aren’t! Each universe can have subtle differences in its laws of physics (APIs) which have been modified by the Master (developer of the site) who has created the universe. The Master may decide that modification of these laws improve the lives of the creatures (JS, HTML, and CSS) who inhabit the universe. But to a visitor from another universe, the Timelord, these rules might seem strange or even dangerous!

The timelord arrives in a new universe via a gateway (script tag) that links all of the universes in the multiverse together.

When first venturing out into the multiverse of the web the timelord will need to protect herself and provide some form of isolation. At first the answer may seem obvious the timelord shall employ the use of a TARDIS. The TARDIS provides a level of protection from the universe it is visiting. The initial version of the TARDIS will most likely be a simple IIFE JavaScript expression.

//TARDIS shell
//timelordTech is not visible outside of the shell.
(function(g) {
  var timelord = {};
  var timelordTech = {};
}(this));

Anything defined within the TARDIS shall stay within the TARDIS. We don’t want to leak timelord technology all over the multiverse!

As the timelord travels she encounters many universes and interacts with the creatures in each. Being a timelord the first thing she wants to do when she arrives is check the local time. In all of the multiverse there is a standard way the timelord can use to find local time. Its known as the Date creature. The Date creature can do many things related to time. But the timelord is interested in only one thing. She wants to get the current timestamp when she arrives.

The timelord arrives in a new universe and encounters the Date creature. And strikes up a conversion:

(function(g) {
  var d = new Date();
  console.log(d.getTime()));
}(this));

Response:

1384248447189

In every universe the timelord has visited so far the Date creature always provides a valid timestamp, which consists of the number of milliseconds since the beginning of the mulitverse.

One day when arriving in a new universe she asks the Date creature for the current time. In this universe instead of receiving a valid timestamp she receives the string

'friday'

The master of this universe is truly an evil one! The unexpected value of “friday” from the Date creature throws our timelord into utter confusion. She no longer knows how to deal with the laws in this universe. She must give up her adventure in this universe and come back prepared to deal with some of the strangenesses she sees.

Modifications to APIs

We have found that our timelord script is failing to operate in one of the host pages. We investigate the issue and find that the API for the Date object has been modified. The “getTime” function is returning a string value instead of the expected timestamp.

Further investigation reveals that someone has decided that the API for retrieving the timestamp from the Date object should be “getTimestamp”. I’m sure the author of this page has a good reason for renaming the function. We are not here to judge its not our website, they can do with it what they want. But we need to make our timelord script more defensive against this sort of problem.

Great news now we know how to deal with the problem. But we must now test the Date object. Getting a timestamp from has become a little more tricky.

(function(g) {
  var d = new Date();
  var ts = d.getTime();
  if(!timelordTechisValidTS(ts)) {
    d = d.getTimestamp();
  }
  timelord.setTime(d);
}(this))

We update our timelord script with the new defensive code and send it on its way across the internet.

Timelord vocabulary is improved.

The timelord travels from universe to universe with her new date creature knowledge. A long time passes without any problems.

Again the timelord arrives in a universe where the Date creature is a little different then the others she has encountered. This time when she asks the Date creature about the current time, it goes into a rage and starts to throw errors. She has somehow enraged this creature by speaking to it in terms that it doesn’t understand!

var ts = d.getTime();
if(!timelordTechisValidTS(ts)) {
  d = d.getTimestamp();
}
timelord.setTime(d);

the Date creature replies:

TypeError: Object [Object Date] has no method 'getTime'

Our timelord script has been killed by the errors thrown by the date creature. Even with the isolation from the TARDIS it isnt enough to defend against an aggressive attack from the Date creature.

Even more complication

We have found another case where the API for the Date object has been changed. This time someone removed the “getTime” function completely so when we try to invoke getTime it throws an exception. In this case there is now no way to get a timestamp from the modified Date object. We cannot get a valid timestamp from this website.

What do we do in this case? We can’t just include our own Date object in our timelord script. Its impossible to include the Date object, because it depends on native code in the browser to get the timestamp. What we need is a way to get a Date object which has not been modified.

The only way to get a Date object which has not been modified is to setup an iframe and execute our timelord script in the iframe. The iframe will provide a clean JavaScript context where we can depend on the API of the objects to be stable and unmodified.

The isolation we used for out initial implementation of the TARDIS is not enough. An IIFE does not provide our script with a clean JavaScript context. We will need to improve the TARDIS and have it construct a same domain iFrame and initialize our timelord script within the iFrame. Then our interaction with the Date object becomes straight forward no matter what site we are running on.

Coming soon…

In the next post I will walk through the setup of a same domain iframe. The various ways a script can be bootstrapped within the iframe. Finally I will describe the differences between the same domain iframe and the cross domain iframe.

One Comment on “IFrames, A TARDIS, and the Multiverse

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

%d bloggers like this: