javascriptoverridingservice-worker

Problem overriding postMessage / onmessage functions in Worker


I want to override the postMessage() function in all Worker created after the override. I am doing this in a browser extension from a content script before page is loaded.

I have tried to simply override it like this:

Worker.prototype.postMessage = function() {
    console.log('post1:');
};

Worker.postMessage = function() {
    console.log('post2');
};

But this does nothing.

I also tried proxying the object creation like this:

const workerTarget = Worker;

const workerHandler = {
    construct(target, args) {
        console.log(`Creating a ${target.name}`);
        console.log('args:' + args);
        var t = new workerTarget(args);
        return t;
    },
  };
  
const workerProxy = new Proxy(workerTarget, workerHandler);
Worker = workerProxy;

This seems to work since I get the console log entries and the worker is not messed up, i.e. it still does it's job.

But if I try to override postMessage() after the Worker is constructed like this:

const workerTarget = Worker;

const workerHandler = {
    construct(target, args) {
        console.log(`Creating a ${target.name}`);
        console.log('args:' + args);
        var t = new workerTarget(args);
        t.postMessage = function(...args2) {
            console.log('post');
        };
        return t;
    },
};

const workerProxy = new Proxy(workerTarget, workerHandler);
Worker = workerProxy;

It does not work, nothing happens to the Worker.

EDIT I tried another approach, using the onmessage property instead, which should let me inspect any message posted by any worker thread to the main script?

const onmessagegetter = Object.getOwnPropertyDescriptor(Worker.prototype, 'onmessage').get;
const onmessagesetter = Object.getOwnPropertyDescriptor(Worker.prototype, 'onmessage').set;
Object.defineProperty(Worker.prototype, 'onmessage', {
  get() {
    console.log('getCalled');
    return onmessagegetter.apply(this);
  },
  set() {
    console.log('setCalled');
    return onmessagesetter.apply(this, arguments);
  }
});

Will this let me inspect all messages posted by any worker? (dedicated/shared/service)

EDIT2 Looks like this will only let me see when the onmessage() is declared not when the event is triggered.


Solution

  • So I still do not know exactly why you cannot override postMessage, so if anyone can give a good explanation please comment.

    I resolved my problem with another approach, pre appending my own script to the Worker script at creation like this:

    const workerHandler = {
        construct(target, args) {
            console.log(`Creating a ${target.name}`);
            console.log('args:' + args);
            
            const request = new XMLHttpRequest();
            request.open("GET", args, false); // `false` makes the request synchronous
            request.send(); // blocks until response
    
            if (request.status === 200) {
                console.log('XHR Success');
            }
            else{
                console.log('XHR Failed');
            }
    
            const sourceBlob = new Blob([request.responseText]);
            const blob = new Blob([ '(' + payload.toString() + ')();' , sourceBlob ], {type: 'application/javascript'});
            const t = new target(URL.createObjectURL(blob));
            
            return t;
        },
    };