Communicating with html windows vs XUL windows

Hi all,
Ok, so I keep hearing that XUL is being deprecated. My plugin (YoutubeMP3Podcaster) uses XUL to pop up a dialog with all sorts of controls for the user to use when they’re downloading a video from youtube.

  I've been playing around trying to re-write the dialog in HTML but I can't figure out any way to pass the download links to the dialog if it's HTML. I think the problem is that today I embed the link that pops up the dialog underneath the video on youtube.com. With XUL I can pass parameters, access the DOM of window.opener, etc, etc to pass the links through. I think I'm running into cross origin problems since the link that opens the window is on youtube but my plugin is either a chrome:// or file:// url (I've tried both).

 Is any of this workable or am I just up a creek? I suppose I could move everything to the toolbar but I kinda liked having it underneath the video.

I’m not sure how they will deprecate XUL windows. As windows are still windows.

You should be communicating (even these days to XUL windows or non-XUL windows) with window.postMessage, and that will continue to work in the future as it is a HTML5 feature.

window.postMessage is the recommended way as it allows transferring of ArrayBuffer and is a async process.

postMessage is primarily for communicating between different content pages. It is essentially a structured event with a convenient wrapper for creating and sending it. It has built in support to address cross-origin security concerns although some responsibility for security still rests with the callers. Although it is obviously intended and designed for communication between separate documents (ie. pages) it is based on a window, hence communication is only between different pages in a particular window. Caution if you’re breaking the default settings to run multiple content processes for tabs in the same window.

Almost by coincidence, communication between different web pages can be used by extensions to submit and receive the same messages. This is handy, but less useful than you might expect. It doesn’t perform cross-process messaging. You can postMessage from the chrome process to a content process, but only by accessing the content window which is a CPOW. Not good! You should use a frame script to call postMessage from an extension, unless you force the relevant page to stay in the parent process.

You have always been able to use custom events to communicate between different pages within the same window, and even with extension code (using a special flag), but there was no security mechanism built into this, so it could be risky depending on what action was taken or data transferred. postMessage automatically includes origin information which you can check to be sure who you are communicating with and to restrict who gets which messages. However there are security glitches when communicating to and from chrome:// urls, and I don’t think it works at all with file:// urls. A postMessage event can be raised by any content, so reacting to it without checking the origin is a security risk, but with chrome messages you can’t currently check the origin. The origin from a chrome event is null, although it is possibly for an extension to spoof itself as any origin it wants using a sandbox. Similarly, postMessage to an addon (chrome:// url) with a targetOrigin specified doesn’t work and you have to specify “*” which is a massive security hole. The current recommendation is not to do it.

One more possible confusion. postMessage is an HTML5 API for window objects., but there is another postMessage which is an SDK API. They look the same, but aren’t. It has been suggested that the SDK postMessage be deprecated in favour of the port API.

1 Like

Oh wow this is super duper enlightening thank you!

This is my situation:
My bootstrap.js spawend a ChromeWorker. My ChromeWorker has sent to bootstrap via transfer, an arraybuffer. I created a new XUL window. I want to send this XUL window a copy of this arraybuffer. I thought I should do postMessage from my bootstrap to the window. I tried setting the arraybuffer from bootstrap directly in the window but I had performance issues - https://bugzilla.mozilla.org/show_bug.cgi?id=1204172

I thought you were the expert on workers :slight_smile: I’m certainly not.

Arraybuffers are slow. To me they seem a lot slower than they should be, an order of magnitude slower than just manipulating the raw data they contain. Plus there are inevitably going to be performance issues passing large amounts of data from one process to another, at least until they implement some sort of virtual memory solution. Maybe the bug will bring about some improvements. About the only thing you can do for now is ensure you don’t block while it is all going on.

Hahah thanks but no expert just lots of toying with them :stuck_out_tongue:

That’s an excellent point about just making sure not to block the gui I’ll double check all that.

If someone used postMessage to transfer an arraybuffer from say bootstrap.js, how can that postMessage back to bootstrap.js? Because I’m doing it right now, and the event.source (as seen in example) parameter of the message event holds null. It should hold the window it came from. I know I don’t have a window, but is there anyway to transfer back to bootstrap.js?

window.postMessage isn’t really set up for chrome/content communication, and probably never will be. It is just a structured event with added security features. The security features don’t work properly when sending from chrome so you really shouldn’t do it at all. This is partly intentional, partly things that could be fixed but probably never will be. Even if you postMessage from chrome window scope, the source will still be null. Your bootstrap.js can obviously receive postMessage events from any window you choose to listen on, but the security problems are even worse. Try using a frame script to communicate between chrome scope and content scope. It allows much better control over two-way communication, does not transfer data between unprivileged and privileged scopes, and it implicitly takes care of the multiprocess issue.

Also, there are lots of not-quite-the-same things called postMessage. I’m not sure I understand them all, but the SDK has a postMessage built in and workers have their own postMessage. I think the SDK postMessage is actually using content workers, so maybe they’re all the same thing in the end.

1 Like

Ah.

The reason I needed to use window.postMessage was to transfer large array buffers. I can now get it into the window. Just now I need to get it out haha.

They told me to use window.postMessage here - https://bugzilla.mozilla.org/show_bug.cgi?id=1204172 - :frowning:

The framescript sends copy, which I’ll end up having to do if no way to transfer out. I made sure to load the window in process though so I can transfer.

Might be the only way to transfer the type of data you have, but it isn’t the right way. All sorts of security issues. Any random web page could send you data and you have no control.

I was thinking some more about this, what about with Services.ww.open and the final argument being a PRUInt8, is that a transfer or a copy? To me it seems the data is shared by both sides.

I don’t know what Services.ww.open is. Do you mean openWindow? Can you even pass arguments to a normal browser window like that?

Oh yeah haha I meant that.

Like for instance this is how I pass a number:

         var sa = Cc['@mozilla.org/supports-array;1'].createInstance(Ci.nsISupportsArray);
         var sa_imon = Cc['@mozilla.org/supports-PRUint8;1'].createInstance(Ci.nsISupportsPRUint8);
         sa.AppendElement(sa_imon);
         sa_imon.data = i;
         var aEditorDOMWindow = Services.ww.openWindow(null, core.addon.path.content + 'panel.xul', '_blank', 'chrome,alwaysRaised,width=1,height=2', sa);

Then in panel.xul I can access with `window.arguments[0].

I’m not sure if this is share or copy. If it’s share (and no copy is done, as copy takes time) that’s totally fine, I would just need to figure out how to do with an arraybuffer then.

So that’s not a normal browser window. The object you pass in is just that, an object. It is the same object in both windows and you can use it to pass data out as well as in. If you want data out, you set it as a property on the object since it is passed by reference, not by value.

I’m not sure how or if this will work across processes, but for now I think the window is always going to be in the same process.