At NetWallet, we need to embed our application in a host page and communicate securely with our backend servers using cross-domain ajax. Some of the standard techniques for performing cross-domain requests won’t work for us: we can’t expect all third parties to proxy requests (this would be practically infeasible, let alone insecure), nor can we use jsonp because we need to set cookies from our domain to verify user and machine identities. Instead, we’ll create a wormhole.
The basic idea is to create an iframe in the host page that loads content from our domain. This is the idea behind the ‘post to iframe’ trick used by Facebook, among others. As a variant of this technique, we’ve been using porthole.js to set up an iframe to which we can post messages, and from which we can receive messages. This works, but we wanted to wrap this low-level interface into something slightly more convenient. We like jQuery’s ajax method, so we’ll try to imitate that. In the end we’ll have a communication channel that lets us quickly and easily talk to another domain almost as if it were right here, which is why we call it a wormhole: it bridges time and space!
On the host page, the wormhole frontend, we create an Ember object (did I mention we’re using Ember.js?) that sets up the porthole windowProxy and listens for messages from it. This object also has an ajax method that emulates jQuery.ajax, taking a standard settings object. When Wormhole.ajax is called, we create a Deferred to handle the result and store this deferred in a dictionary, indexed by a unique request id. Then, we simply send the settings object through the porthole to be handled on the other side, and we return a promise that the deferred will eventually be fulfilled. When the response comes back from the porthole, Wormhole.onResponse is called and we simply pop the matching deferred out of the dictionary and resolve or reject it, depending on whether the request succeeded or failed.
For convenience, we even handle ajax requests that are made before the iframe has loaded by stuffing those requests into a queue and then sending them when we get a message that the porthole is ready. That way clients can use the Wormhole immediately after it has been created, without themselves waiting for it to be established.
To make this all work the backend page which is pulled down into the iframe from wormholeUrl runs a simple script that sets up the porthole windowProxy from its side, sends a ready message, and then listens for requests posted from the frontend. When a request comes in, it fires off a real jquery ajax call, no cross-domain hoops to jump through, and then sends a response message back through the porthole when the request is complete, indicating whether the call succeeded or failed.
Here’s the code:
Et voila! We can now make cross-domain requests through our iframe using the convenient jQuery.ajax interface. We’re working on interesting problems like these at NetWallet every day, and we’re hiring!