Detect if URL supports HTTP2 using AJAX request in Chrome Extension?
Asked Answered
S

2

16

I want the user to be able to enter their website URL into an input box that is part of a Chrome Extension and the Chrome extension will use an AJAX request or something similar to detect and tell the user if the server behind the URL supports sending responses via HTTP2. Is this possible?

Maybe the WebRequest has a way of picking up this information? Or the new Fetch API? Could your request tell the server somehow that only HTTP2 replies are understood? I can't see an obvious way.

I know you can use window.chrome.loadTimes().connectionInfo to get the protocol of the current page but this requires loading the whole page which I don't want to do.

Example URLS:

Delivered over HTTP2: https://cdn.sstatic.net/

Delivered over HTTP 1.1: https://stackoverflow.com/

Sac answered 20/12, 2016 at 21:8 Comment(5)
You can probably use some online test tool like KeyCDN via API or parsing the response.Pantalets
@wOxxOm That's an option but I'd rather not have to worry about API key limits if the extension gets popular.Sac
Another idea (don't ask me for details please, hopefully someone else will give a proper answer): 1) start loading the URL in an iframe 2) use webRequest API to strip X-Frame headers from the response - see answers on stackoverflow, 3) abort loading immediately in the autoinjected content script (use "all_frames": true in manifest) and send a message with chrome.loadTimes().connectionInfo to your background/popup script.Pantalets
@fstr, Do you have a list of websites which use HTTP/2 against which to test solutions (I can find some, but a list of ones you are interested in helps)? To confirm my understanding: Your user enters a URL into an input box in a popup and you want to be able to tell the user, by changing the DOM of that popup, the protocol (HTTP 1.1, or HTTP/2) which is used by that URL. Do you have a minimal reproducible example which implements everything, except the check, which surrounds this scenario? If so, please provide it. Providing a minimal reproducible example would significantly reduce the effort needed to even begin to test solutions.Covin
@wOxxOm, Given that it is desired to use URLs provided by the user at runtime, using tabs.executeScript() would be much more appropriate than a manifest.json content_scripts entry. The only way to use a manifest.json content_scripts* entry here would be to have it load into <all_urls>`, which would be an inappropriate burden to place on every single page and frame the user opens. Other than that, the general concept behind the approach appears viable (various refinements, more appropriate for an answer than comments, suggest themselves).Covin
S
1

HTTP/2 responses require a "status" response header - https://http2.github.io/http2-spec/#HttpResponse, so to check whether the response is using HTTP/2, you can use the chrome.webRequest.onHeadersReceived event with "responseHeaders" in extraInfoSpec. For example, with your test cases:

chrome.webRequest.onHeadersReceived.addListener(function(details) {
    var isHttp2 = details.responseHeaders.some(function(header) {
        return header.name === 'status';
    });
    console.log('Request to ' + details.url + ', http2 = ' + isHttp2);
}, {
    urls: ['https://cdn.sstatic.net/*', 'http://stackoverflow.com/*'],
    types: ['xmlhttprequest']
}, ['responseHeaders']);

// Tests:
fetch('http://stackoverflow.com');
fetch('https://cdn.sstatic.net');
Savagery answered 23/12, 2016 at 12:2 Comment(2)
Nice observation! It seems to be true for the example URLs. However, how reliable is this? Do any HTTP 1 servers return status headers? Do other protocols do this?Sac
@Sac It is not a reserved header, so HTTP/1 servers can set the header too if they wish. If you want to have the most reliable result, you have to insert a frame and overwrite several response headers, including x-frame-options and content-security-policy. But if the response is redirected elsewhere (to another domain for example), you wouldn't know whether the server supports HTTP/2 or not.Savagery
S
0

EDIT: Apparently you can do this with the iframe and webRequest trick! I found a reference gist (but I haven't tested it myself though):

https://gist.github.com/dergachev/e216b25d9a144914eae2

OLD ANSWER

You probably won't able able to do this without an external API. Here's why

1) Using ajax only requires that the server of the url to be tested sends CORS headers back to the user, otherwise the browser will not accept it.

2) You could create an iframe on the fly and use chrome.loadTimes().connectionInfo in the iframe contentWindow but if the server sends X-Frame-Options: Deny header the browser won't let you load the url in the iframe either.

3) Stripping the X-frame headers via webRequest API as mentioned here

Getting around X-Frame-Options DENY in a Chrome extension?

will likely not work, afaik Chrome extension are not allowed to modify the response body.

Possible solutions

1) The problems above could be solved using a simple proxy that adds the appropriate headers. Here's a reference on how to do it using Nginx

http://balaji-damodaran.com/programming/2015/07/30/nginx-headers.html

2) Just create a custom API that does the request for you server-side and parses the result to check for http2 support. If your extension gets popular it would still be fairly easy to scale it up e.g via caching and horizontal scaling.

Hope this helps!

Submarginal answered 22/12, 2016 at 12:32 Comment(2)
Are you sure you can't strip out of x-frame-options header? I've used the webrequests API to strip out x-frame-options + CSP headers to allow an iframe to be shown in an internal Chrome Extension page and it works as expected.Sac
Actually you might be right about this. I found an extension that can do just that chrome.google.com/webstore/detail/ignore-x-frame-headers/… (see the edited answer above for code reference)Submarginal

© 2022 - 2024 — McMap. All rights reserved.