admin管理员组文章数量:1326638
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:
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 / 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('').
- Examine the resulting error message that appears in the console: Refused to load the script '.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 .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?
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./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.').
- Examine the resulting error message that appears in the console: Refused to load the script 'https://www.yahoo./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/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?
- Why can't you just remove the offending header in the response? – dsign Commented Jul 27, 2017 at 14:04
- @dsign According to developer.mozilla/en-US/docs/Web/API/Response/headers, Response.headers is read-only. Also, my understanding is that this happens as the response is received, there is no time or place for my script to jump into the middle of the processing and remove the offending header. The browser handles all of it. I only get access at the end. – Josh Commented Jul 27, 2017 at 14:10
- Sorry for not being clear. I meant, why can't you remove the offending header on the server-side? – dsign Commented Jul 27, 2017 at 14:16
- Ah. Well I have no control over the server, or any other server. I am writing an app in javascript that sends fetch requests to a variety of other servers. There is not even a pre-determined or apriori-piled list of which other servers are contacted. – Josh Commented Jul 27, 2017 at 14:18
- 1 Okey, I see your pain now. Are you sure then that you not going against plain-old CORS protections? – dsign Commented Jul 27, 2017 at 14:27
1 Answer
Reset to default 6 +250After following along with your test case I was able to resolve this (example of the) issue in the following way, though I don't know that it applies to all more general cases:
- Use
chrome.webRequest
to intercept responses to the extension's requests. - Use the blocking form of
onHeadersRecieved
to strip out headers containingrel=preload
- Allow the response to proceed with the updated headers.
I have to admit I spent a lot of time trying to figure out why this seemed to work, as I don't think stripping the Link headers should work in all cases. I thought that Server Push would just start pushing files after the request is sent.
As you mentioned in your additional note about SETTINGS_ENABLE_PUSH
much of this is in fact baked into chrome and hidden from our view. If you want to dig deeper I found the details at chrome://net-internals/#http2
. Perhaps Chrome is killing files sent by Server Push that don't have a corresponding Link header in the initial response.
This solution hinges on chrome.webRequest
Docs
The extension's background script:
let trackedUrl;
function foo(url) {
trackedUrl = 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)
}
chrome.webRequest.onHeadersReceived.addListener(function (details) {
let newHeaders;
if (details.url.indexOf(trackedUrl) > -1) {
newHeaders = details.responseHeaders.filter(header => {
return header.value.indexOf('rel=preload') < 0;
})
}
return { responseHeaders: newHeaders };
}, { urls: ['<all_urls>'] }, ['responseHeaders', 'blocking']);
The extension's manifest:
{
"manifest_version": 2,
"name": "Example",
"description": "WebRequest Blocking",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": [
"back.js"
]
},
"content_security_policy": "script-src 'self'; object-src 'self'",
"permissions": [
"<all_urls>",
"background",
"webRequest",
"webRequestBlocking"
]
}
Additional Notes:
I'm just naively limiting this to the latest request url from the extension, there are
webRequest.requestFilters
baked intochrome.webRequest
you can check out hereYou'll probably also want to be much more specific about which headers you strip. I feel like stripping all the Links will have some additional effects.
This avoids proxys and does not require setting a Link header in the request.
This makes for a pretty powerful extension, personally I avoid extensions with permissions like
<all_urls>
, hopefully you can narrow the scope.I did not test for delays caused by blocking the responses to delete headers.
本文标签: javascriptHow do I opt out of HTTP2 server push when using fetchStack Overflow
版权声明:本文标题:javascript - How do I opt out of HTTP2 server push when using fetch? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742209019a2433357.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论