Question

I'm working on a firefox addon which needs support for ajax requests. The requests will all be sent to the 'messagebeam.tagpulse.nl' domain, so I added it to the permissions in package.json like this:

{
    "name": "messagebeam",
    "title": "Message Beam for Android™",
    "id": "jid1-j831e5AVhpvjDA",
    "description": "With one click bidirectionally beam anything you want between Chrome and your Android device!",
    "permissions": {
        "cross-domain-content": ["http://messagebeam.tagpulse.nl/"]
    },  
    "author": "TwZ",
    "license": "MPL 2.0",
    "version": "0.3"
}

So far so good. In my main.js, I defined a (very basic) widget and a panel (in main.js) to demonstrate the problem:

var testPanel = require("sdk/panel").Panel({
  width:430,
  height:500,
  contentURL: data.url("test.html"),
  contentScriptFile: [
                        data.url('scripts/jquery-2.1.0.js'),
                        data.url('test.js')
                      ]
});
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");
var widget = widgets.Widget({
  id: "test-popup",
  label: "Message Beam",
  contentURL: data.url("img/test.png"),
  panel: testPanel
});

The test.html is very basic (no content):

<html>
    <head>
    </head>
    <body>
        No content
    </body>
</html>

The test.js (the actual code that produces the permission denied error):

$(document).ready(function() {
    xmlhttp=new XMLHttpRequest();
    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            console.log('finished');
            console.log(xmlhttp.responseXML);
            console.log('reported xml');
        }
    }
    xmlhttp.open("GET","http://messagebeam.tagpulse.nl/test/test2.php",true);
    xmlhttp.send(); 
});

The xml returned is as follows (with content-type: text/xml response header, test using http://messagebeam.tagpulse.nl/test/test2.php):

<?xml version="1.0" encoding="UTF-8" ?>
<test>
  text
</test>

And now the question: why does the console.log(xmlhttp.responseXML) line produce the following error:

console.log: messagebeam: finished
System JS : ERROR resource://gre/modules/XPIProvider.jsm -> jar:file:///c:/users/js/appdata/local/temp/tmpfcjrsq.mozrunner/extensions/jid1-j831e5AVhpvjDA@jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/loader/sandbox.js -> resource://gre/modules/commonjs/sdk/content/content-worker.js:81
                     Error: Permission denied to access property 'toJSON'
Was it helpful?

Solution

It's first a good idea to look at the line of code mentioned in the error message. Here it is resource://gre/modules/commonjs/sdk/content/content-worker.js, line 81 - this is Add-on SDK code integrated into the browser. In Firefox 26 this line says:

let str = JSON.stringify(args, replacer);

This code belongs to the messaging mechanism of content workers. toJSON is being called implicitly by JSON.stringify on the objects that are being serialized.

Obviously, accessing xmlhttp.responseXML doesn't trigger any content worker events. However, console.log() does - right below the problematic createPipe method in content-worker.js you can see an injectConsole method. This one provides console API for content workers, and it will use messaging to forward any calls to the main extension code.

At that point the issue should be obvious: even though the "real" console.log() method can deal with parameters of type XMLDocument, the one provided to content workers cannot - it expects an object that can be serialized to JSON. Calling console.log(xmlhttp.responseText) should work however. Also, console.log(new XMLSerializer.serializeToString(xmlhttp.responseXML)) might work (I'm not sure whether the XMLSerializer constructor is defined in the worker context).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top