I seek to manipulate the XMLHttpRequest done by a website using Greasemonkey (version 4.9 installed). Interception should be simple (How can I intercept XMLHttpRequests from a Greasemonkey script?) but does not work for me. Maybe things changed with newer versions of Greasemonkey?
I obviously tried the examples in the linked question, but they don't have any effect - nothing printed in the console although I have an console.log(...)
in my customised open function.
Next, I gave unsafeWindow
a try. It should not be needed. My userscript runs with @grant none
and documentation (see here) says my script should run in the content scope.
With unsafeWindow
I get an effect but it breaks XMLHttpRequest completely
// ==UserScript==
// @name Test
// @version 1
// @include *
// @run-at document-start
// @grant none
// ==/UserScript==
"use strict";
let realOpen = unsafeWindow.XMLHttpRequest.prototype.open
console.log("Real: " + realOpen)
unsafeWindow.XMLHttpRequest.prototype.open = function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
};
window.addEventListener ("load", function() {
console.log ("Page loaded");
});
console.log("Unsafe: ", unsafeWindow.XMLHttpRequest.prototype.open.toString())
console.log("Normal: ", XMLHttpRequest.prototype.open.toString())
This gives following output in console:
Real: function open() {
[native code]
}
Unsafe: function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
}
Normal: function open(method, url) {
// only include method and url parameters so the function length is set properly
if (arguments.length >= 2) {
let newUrl = new URL(arguments[1], document.location.href);
arguments[1] = newUrl.toString();
}
return origOpen.apply(this, arguments);
}
==> Page loaded
As mentioned, function of XMLHttpRequest is broken. When I use the Firefox developer console to have a further look I get this
>> window.XMLHttpRequest.prototype.open
Restricted { }
Any properties set on window
(like window.foobar = "foobar"
) do not exist in console, but those set on unsafeWindow
do. I assume this has to do with Greasemonkey's sandboxing.
Why are there two versions of XMLHttpRequest even when I use @grant none
? Why is my custom function restricted? Can I avoid that? Why does it work without problems when I install event listener on window?
Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with @grant none and documentation (see here) says my script should run in the content scope.
This is wrong for Greasemonkey 4 as stated in its announcement:
Due to the more limited abilities that the new extension system gives us, we are currently unable to make @grant none scripts work in the same way. Most importantly, they have a different connection to unsafeWindow. For the short term at least, it's a good idea to adopt cloneInto and exportFunction.
See also this other question Firefox doesn't respect Object.defineProperty() from a Greasemonkey script?
This change explain the observations, but no idea why adding listener to window work.