I have a Chrome extension that can (if you allow access to file URLs) grab your local pdf file that you have open in chrome and send it on to our API for processing. This is done by fetching the pdf with XMLHttpRequest
to file:///Users/user/whatever/testfile.pdf
from the background script.
When migrating to manifest v3 for a Chrome extension the background script becomes a service worker. In a service worker only fetch
is available, not XMLHttpRequest
. Problem is, fetch only supports http and https, not file:// urls. So how can I make the same feature of having the Chrome extension fetching/getting the local file?
EDIT: Things I also tried:
Making the XMLHttpRequest from injected iframe as suggested by answer. This gives error
net:ERR_UNKNOWN_URL_SCHEME
when making the requestMaking the XMLHttpRequest from injected content script. This gives error
Access to XMLHttpRequest at 'file:///.../testfile1.docx.pdf' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
From what I can understand from a lot of research access to file://
is in general blocked and Chrome extension background scripts used to be an exception to this. Seems to me it was never allowed from content scripts or action popups.
My manifest.json for reference:
{
"manifest_version": 3,
"name": "..",
"version": "0.1",
"icons": {
"16": "assets/icon-16x16.png",
"48": "assets/icon-48x48.png",
"128": "assets/icon-128x128.png"
},
"action": {
"default_title": ".."
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"webRequest",
"activeTab",
"scripting",
"storage",
"unlimitedStorage",
"identity",
"pageCapture"
],
"host_permissions": [
"<all_urls>"
],
"web_accessible_resources": [{
"resources": ["iframe.html"],
"matches": [],
"extension_ids": []
}]
}
The content script is injected programmatically (using webextension-polyfill
for promise support)
browser.action.onClicked.addListener(async (tab: Tab) => {
await browser.scripting.executeScript({files: [ "inject.js" ], target: {tabId: tab.id}});
});