Search code examples
javascriptfirefoxfirefox-addonfirefox-addon-webextensions

webRequest.onHeadersReceived not firing


I am trying to load a website inside an iFrame but the server is sending the X-Frame-Options: SAMEORIGIN header so I've tried to use onHeadersReceived to modify the headers though I cannot get it to work.

manifest.json

{

  "manifest_version": 2,
  "name": "__MSG_extensionName__",
  "description": "__MSG_extensionDescription__",
  "default_locale": "en",
  "version": "0.1",

  "author": "author",
  "homepage_url": "https://github.com/",

  "icons": {
    "48": "assets/icons/logo.png"
  },

  "background": {
    "page": "../../background.html"
  },

  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["scripts/dist/bundle.js"],
      "css": ["assets/css/main.css"]
    }
  ],

  "permissions": [
    "tabs",
    "webRequest",
    "contextMenus",
    "webNavigation",
    "webRequestBlocking"
  ],

  "web_accessible_resources": [
    "assets/icons/logo.png"
  ]

}

background.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="module" src="scripts/dist/contextMenu.js"></script>
        <script type="module" src="scripts/dist/modifyHeaders.js"></script>
    </head>
</html>

contextMenu.js

browser.contextMenus.create( {
    id: "customsearch",
    title: "Search",
    contexts: ["selection"]
} );


// Context menu onClicked listener
browser.contextMenus.onClicked.addListener( (info, tab) => {
    if (info.menuItemId = "custom-search") {
        sendMessageToTab(tab, info);
    }
} );


function sendMessageToTab(tab, info) {
    browser.tabs.sendMessage(
        tab.id,
        { query: info.selectionText }
    );
}

background.js

var extraInfoSpec = ['blocking', 'responseHeaders'];
var filter = {
    urls: ['<all_urls>'],
    tabId: -1
};

// Bypass X-Frame-Options
browser.webRequest.onHeadersReceived.addListener(
    modifyHeadersCallback,
    filter,
    extraInfoSpec
);


// onHeadersReceived Callback
function modifyHeadersCallback(details) {
    let modifiedResponseHeaders = details.responseHeaders.filter(
        header => !(header.name.toLowerCase() == 'x-frame-options' || header.name.toLowerCase() == 'content-security-policy')
    );

    return {responseHeaders: modifiedResponseHeaders};
};

Context menu works as expected, the problem is with the browser.webRequest.onHeadersReceived listener which seems to not get fired at all as I don't get any errors or logs to the console. I did any extensive search and tried most of the solutions I've found but nothing worked for my case. Can you spot anything wrong in my approach?


Solution

  • Firefox

    All you need is to remove tabId: -1 from your filter object:

    browser.webRequest.onHeadersReceived.addListener(
      modifyHeadersCallback,
      { urls: ['<all_urls>'] },
      ['blocking', 'responseHeaders']
    );
    

    Chrome

    Modern Chrome requires the extraHeaders mode in extraInfoSpec parameter so the universal code for iframes would look like this:

    browser.webRequest.onHeadersReceived.addListener(
      modifyHeadersCallback,
      { urls: ['<all_urls>'], types: ['sub_frame'] },
      // Modern Chrome needs 'extraHeaders' to see and change this header,
      // so the following code evaluates to 'extraHeaders' only in modern Chrome.
      ['blocking', 'responseHeaders', chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS]
        .filter(Boolean)
    );
    

    And of course "permissions" in manifest.json should contain the URLs you want to process e.g. in this case it's "<all_urls>".

    So, this is either a bug or an intentional change, which wasn't documented yet, so if someone wants to report it please open a new issue on https://crbug.com. I guess it's intentional because the extraHeaders mode means this header is handled in the internal network process, which is separate from the browser process.