It’s been a little while since I last wrote about Cross-Window Messaging in Firefox 3 using postMessage and since that time it’s since a few API updates.
Specifically the postMessage API has become much simpler and has stronger security brought into mind.
If you’re unfamiliar with postMessage here’s a quick re-cap: It’s a way to communicate simple string-based messages across browser windows (this includes frames, iframes, and popups). It’s a part of HTML 5 specification and is included in Firefox 3, Internet Explorer 8, WebKit Nightlies, and Opera 9.5.
Here’s the revised process works using the final postMessage API (currently only works in Firefox 3):
Sending
Sending is still done by calling the postMessage method on a window object. The one addition is that an extra targetOrigin argument is now required. This argument allows you to specify the exact origin that you’re expecting this message to reach (this can help prevent malicious attempts to redirect the contents of frames to intercepting pages).
It’s highly recommended that you provide an origin, but if you don’t wish to you can specify “*” instead (which will work for any origin).
Demo: https://johnresig.com/apps/message/
<iframe src="http://dev.jquery.com/~john/message/" id="iframe"></iframe> <form id="form"> <input type="text" id="msg" value="Message to send"/> <input type="submit"/> </form> <script> window.onload = function(){ var win = document.getElementById("iframe").contentWindow; document.getElementById("form").onsubmit = function(e){ win.postMessage( document.getElementById("msg").value, "http://dev.jquery.com" ); e.preventDefault(); }; }; </script>
Receiving
The primary change to receiving is that you must now listen for the incoming event on the window object, instead of the document. This is a smart API change (keeping document/window straight would’ve surely caused implementation problems).
Additionally, in the incoming event object, there use to be a number of properties made available for determining the origin of the request. Now, however, there is only a single property: event.origin
. This property contains the base origin from which the request is coming.
For example in the above demo the full URL is “https://johnresig.com/apps/message/” but the event.origin
is just “https://johnresig.com”. It’s highly recommended that you verify the incoming origin of the request in order to prevent any malicious attempts to inject data.
Additionally, even though it’s not done below, it’s important to do some validation on the incoming message contents. It’s entirely possible that the origin page may have been compromised so you’ll need to take that into consideration.
Demo: http://dev.jquery.com/~john/message/ (Use the above demo to see this page in action)
<b>This iframe is located on dev.jquery.com</b> <div id="test">Send me a message!</div> <script> window.addEventListener("message", function(e){ if ( e.origin !== "https://johnresig.com" ) return; document.getElementById("test").textContent = e.origin + " said: " + e.data; }, false); </script>
I’m pleased with these changes and I’m glad that there were able to make it in to Firefox 3 in time. I hope we see some more implementation convergence here as it would be really good to have all four browsers with an HTML 5 feature in it.
Peter Kasting (May 22, 2008 at 9:51 pm)
You didn’t note that the API switched from being synchronous to asynchronous.
Also, to be nitpicky, this isn’t the “final version” of the API any more than the last one, it’s just the most recent version. Not that I expect changes; just that HTML5 itself is not final.
John Resig (May 22, 2008 at 11:41 pm)
@Peter: Yep, it absolutely did change to asynchronous – thankfully, however, it hasn’t affected any applications or examples that I could find – so there’s really no point in discussing it.
It’s final in the respect that it’s shipping in a browser. Prior to Firefox 3 shipping (which will occur within the next couple weeks) there was no browser with a postMessage implementation – thus it was open to adjusting. Now that one is out it’ll be significantly harder for any adjustments to occur, for fear of breaking existing web applications. That’s final enough to me.
Lennie (May 23, 2008 at 3:02 am)
sync. was already possible, a simple javascript could do it.
async. is what makes this usefull.
Although I don’t have any use for it now.
RichB (May 23, 2008 at 3:20 am)
Your definition of “final” could have applied to IE’s getElementById() implementation.
And we know the abuse that gets.
John Resig (May 23, 2008 at 8:07 am)
@RichB: What does Internet Explorer’s getElementById have to do with anything? It doesn’t follow any specification – unlike postMessage which follows a very clear specification. The code that’s shipping with Firefox 3 is the final version of the specification that’s going to be put in an active browser – any future changes will break web sites.
Steve Souders (May 23, 2008 at 11:20 am)
Does using postMessage generate Windows events that clientside performance applications (packet sniffers, exes and IE BHOs) could track for measuring response times?
Jeff Walden (May 23, 2008 at 12:23 pm)
@Steve: I don’t think so; it’s just using the internal event loop in Firefox to do the message sending, so anything like that would have to be a generic hook that doesn’t exist, to the best of my knowledge.