views:

289

answers:

1

I have a Greasemonkey userscript which runs most of its code in an unprivileged context by inserting a <script> tag like so:

function code {
  ...
}

var script = document.createElement("script");
script.type = "application/javascript";
script.innerHTML = "(" + code + ")();";
document.body.appendChild(script);

This avoids the need to do dangerous things with unsafeWindow.

However, I my code needs to get information from an API on another domain which doesn't support JSONP. GM_xmlhttpRequest can access other domains, but is only available in the privileged Greasemonkey context.

I'd like to write a function which provides a limited interface and makes exactly the API call I need using GM_xmlhttpRequest, and then expose that (theoretically safe) function to the normal page context. My first attempt at that was something like:

unsafeWindow.foo = function() {
  console.log("Foo!");
  console.log(GM_xmlhttpRequest.toString());
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://www.example.net/",
    headers: {
      "User-Agent": navigator.userAgent,
      "Accept": "text/html"
    },
    onload: function(response) {
      console.log(response);
      unsafeWindow.console.log(response);
      alert(response);
      unsafeWindow.alert(response);
    }
  });
  console.log("Bar!");
};

Interestingly, when I call foo() from the page context, I see "Foo!", the stringified GM_xmlhttpRequest and "Bar!" in the console log. However, I never get the response in the console or in an alert. If I make the GM_xmlhttpRequest on its own in the GM context, I get both alerts and log messages.

The question is: is what I'm trying to do even possible? Or is there another way to accomplish the same thing?

+1  A: 

Aha! The answer has been posted to a similar question.

Greasemonkey does this very intentionally, and provides a simple workaround on the 0.7.20080121.0 compatibility page:

unsafeWindow.foo = function() {
  window.setTimeout(GM_xmlhttpRequest, 0, {
    // ...
  });
};

That works.

Peeja