Browser extension: monkey patching fetch responses from the actual webpage

203 views Asked by At

I'm working on a browser extension, currently running script under content_scripts.

I'm trying to intercept the response from fetch request from the website my extension is running onto.

I found a lot of answers on how to monkey patch fetch requests to intercept the response. But my issue is that, while I can intercept my own requests just fine (in Chrome), I can't access the ones from the website itself.

Apparently there is a way to inject code in a tab, but, again, I'm running in the issue that I can't run browser.tabs from content_script

In javascript, what are some ways I could get an extension to intercept the fetch requests (specifically the response) from a webpage?

Probably not very relevant, but my current code is a slight adaptation of a stackoverflow answer as follow:

const isFirefox = navigator.userAgent.toLowerCase().includes('firefox');

if(!isFirefox){
    const {fetch: origFetch} = window;
    let responseData = null;
    window.fetch = async (...args) => {
      console.log("fetch called with args:", args);
      let response = await origFetch(...args);
      console.log("test2"); //Firefox will never get here
      // work with the cloned response in a separate promise
      // chain -- could use the same chain with `await`. 
      await response
        .clone()
        .json()
        .then(function(data){
            console.log("intercepted response data:", data);
            responseData = data;
            })
        .catch(err => console.error(err));

      // the original response can be resolved unmodified:
      console.log(responseData);
      //return response;

      // or mock the response: 
      return new Response(JSON.stringify(responseData));
    };
}
1

There are 1 answers

0
FMaz008 On

Here's a way I was able to accomplish my goal:

In the content_scripts, I added the following code to inject a javascript file in the main world:

//Inject the script into the main environment.
var s = document.createElement('script');
s.src = chrome.runtime.getURL('scripts/attach.js');
s.onload = function() { this.remove(); };
// see also "Dynamic values in the injected code" section in this answer
(document.head || document.documentElement).appendChild(s);

and then my scripts/attach.js will be executed in the main world/environment and monkey patch the fetch method to intercept the response and allow to modify it:

const origFetch = window.fetch;

let responseData = {};

window.fetch = async (...args) => {
  
  let response = await origFetch(...args);

  //Will only work for content which can be encoded to JSON. This code should not be used for images or other binary content. For those content, just return response.
      await response
        .clone()
        .json()
        .then(function(data){
            responseData = data;
            })
        .catch(err => console.error(err));
        
    //Modify responseData
      
    //Return mocked response
    return new Response(JSON.stringify(responseData));
  
    //Return unaltered response
    //return response;
  }
};