I am not sure if this is a bug, or a mis-configuration of my manifest file, but the <all_urls>
permission is not working with content script injection. Here is a simple example that causes the error
manifest.json :
{
"manifest_version": 2,
"name": "Bug?",
"version": "1",
"description": "This seems to be a bug",
"minimum_chrome_version": "50",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"<all_urls>",
"tabs",
"webNavigation"
]
}
background.js:
chrome.webNavigation.onBeforeNavigate.addListener(info => {
chrome.tabs.executeScript(info.tabId, {
frameId: info.frameId,
code: 'console.log("works")',
runAt: 'document_start'
}, () => {
if(chrome.runtime.lastError)
console.error(chrome.runtime.lastError.message)
})
})
I want my content scripts to run before any html is processed by the browser in a page and all of its subframes. I am aware that I can specify my content scripts in the manifest file. This doesn't, however, let me choose to run a different content script for root and subframes. The above code is hence a good toy example of what my eventual code may look like.
Content scripts fail to execute with the following error, for each frame:
Cannot access contents of url "<some url>". Extension manifest must request permission to access this host.
What?... <all_urls>
doesn't mean all urls?
If I change chrome.webNavigation.onBeforeNavigate
to chrome.webNavigation.onCommitted
, the injection works as expected (with the exception of about:blank
pages, which can be fixed easily). This does not guarantee, however, that my content script is run before any html is processed.
Any thoughts?
You're running into a bad tangle of timing issues here.
If you try to inject before onCommitted
happens, you're effectively trying to inject into the old document, since it did not change yet.
It's an educated guess, but what might be happening is a race condition when your permissions are evaluated for the old URL but by the time injection is actually happening the navigation took effect and the origin is now different.
There isn't a good timing in relation to webNavigation
/tabs
events for run_at: "document_start"
to be scheduled. It effectively only works as you intend it to if you specify it in the manifest (or the still-experimental content script action for declarativeContent
API).
Now, speaking of your problem:
This doesn't, however, let me choose to run a different content script for root and subframes.
That's not true at all. You can branch your logic depending on your position in the iframe hierarchy:
if (window.parent != window) {
// Subframe
} else {
// Main frame
}
So, you should rely on manifest injection for "document_start"
scripts, and you can implement a different logic for subframes synchronously.