I am writing a basic app in Javascript that uses the new fetch API. Here is a basic example of the relevant portion of the code:
function foo(url) {
const options = {};
options.credentials = 'omit';
options.method = 'get';
options.headers = {'Accept': 'text/html'};
options.mode = 'cors';
options.cache = 'default';
options.redirect = 'follow';
options.referrer = 'no-referrer';
options.referrerPolicy = 'no-referrer';
return fetch(url, options);
}
When making a fetch request I occasionally see errors appear in the console that look like the following:
Refused to load the script '<url>' because it violates the following Content Security Policy directive ...
After some reading and learning about HTTP/2, it looks like this message appears because the response is pushing back a preloaded script. Using devtools, I can see the following header in the response:
link:<path-to-script>; rel=preload; as=script
Here is the relevant portion of my Chrome extension's manifest.json file:
{
"content_security_policy": "script-src 'self'; object-src 'self'"
}
Here is documentation on Chrome's manifest.json format, and how the content security policy is applied to fetches made by the extension: https://developer.chrome.com/extensions/contentSecurityPolicy
I did some testing and was able to determine that this error message happens during fetch, not later when parsing the response text. There is no issue where a script element gets loaded into a live DOM, this all happens at the time of the fetch.
What I was not able to find in my research was how to avoid this behavior. It looks like in the rush to support this great new feature, the people that made HTTP/2 and fetch did not consider the use case where I am not fetching the remote page for the purpose of displaying it or any of its associated resources like css/image/script. I (the app) will not ever later be using any associated resource; only the content of the resource itself.
In my use case, this push (1) is a total waste of resources and (2) is now causing a really annoying and stress-inducing message to sporadically appear in the console.
With that said, here is the question I would love some help with: Is there a way to signal to the browser, using manifest or script, that I have no interest in HTTP/2 push? Is there a header I can set for the fetch request that tells the web server to not respond with push? Is there a CSP setting I can use in my app manifest that somehow triggers a do-not-push-me response?
I've looked at https://w3c.github.io/preload/ section 3.3, it was not much help. I see that I can send headers like Link: </dont/want/to/push/this>; rel=preload; as=script; nopush
. The problem is that I do not already know which Link headers will be in the response, and I am not sure if fetch even permits setting Link headers in the initial request. I wonder if I can send some type of request that can see the Link headers in the response but avoids them, then send a followup request that appends all the appropriate nopush headers?
Here is a simple test case to reproduce the issue:
- Get a dev version of latest or near latest chrome
- Create an extension folder
- Create manifest with similar CSP
- Load extension as unpacked into chrome
- Open up the background page for the extension in devtools
- In console type fetch('https://www.yahoo.com').
- Examine the resulting error message that appears in the console: Refused to load the script 'https://www.yahoo.com/sy/rq/darla/2-9-20/js/g-r-min.js' because it violates the following Content Security Policy directive: "script-src 'self'".
Additional notes:
- I do not want to use a proxy server. A clear explanation as to why that would be my only option would be an acceptable answer.
- I do not know the urls that will be fetched at the time of configuring the CSP.
- See https://www.rfc-editor.org/rfc/rfc7540#section-6.5.1 which states in relevant part that "SETTINGS_ENABLE_PUSH (0x2): This setting can be used to disable server push (Section 8.2). An endpoint MUST NOT send a PUSH_PROMISE frame if it receives this parameter set to a value of 0." Is there a way to specify this setting from script or manifest or is it baked into Chrome?
HTTP/2
is related to Question? – RexfordHTTP/2
? Is the issue the preflight request Why does Fetch API Send the first PUT request as OPTIONS? – Rexfordhttp/1.1 ir9.fp.bf1.yahoo.com (ApacheTrafficServer)
. I have noticed that OPTIONS requests sometimes appear on the Network tab of devtools in Chrome after running my script. I am specifying cors mode in fetch options as shown in my question, so this is expected, and is not the thing giving me trouble. – CamiOPTIONS
request first #42311518? – RexfordYQL
as a proxy to make request? – Rexford