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/
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');
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!
Related
I'm getting this error when I try to use $.get on a non-secure site (ie. http, not https):
jquery.min.js:4 Mixed Content: The page at '...' was loaded over HTTPS, but requested an insecure script 'http://api.openweathermap.org/data/2.5/weather?lat=50&lon=2?callback=jQuery...'. This request has been blocked; the content must be served over HTTPS.
I've been trying to think of work-around solutions to this. The problem is a fixed one, since the server is hosted by OpenWeather.org and it's a non-secure site (ie. http, not https).
This is my request code:
$.get("https://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&APPID=123456", function(data) {
tempC = data.weather.main.temp / 10; // OpenWeather API returns Celsius * 10
rain = data.rain["3h"];
clouds = data.clouds.all;
});
Simply changing the request URL to https://api.openweathermap.org... doesn't work, of course. Tried it and didn't work.
The only solution I can think of right now is to find another weather API that is free to use for my project, but I'd like to know if there's a way to still use OpenWeathermap's API, given that it's http. Curious to know this because it seems quite wasteful to have to dismiss certain APIs just because it's http and not https.
Found another post on SO about the same "mixed content" issue. It's helpful and points to many other resources to solve the problem.
The asker ended up dropping openweathermap API (because it's served over HTTP) and using forecast.io's API instead (served over HTTPS while still free).
Using Open Weather Map which is HTTP only through an HTTPS website and NOT get mixed content warning
so, the Problem is, that you run your code on a HTTPS site(JSFiddle and Coodepen). Your browser will not allow HTTP-Connections on a HTTPS site for security-reasons. You can solve that issue by either forcing HTTP on the page where you run your code(try to run a code from a local file or localhost) or you could create a HTTPS -> HTTP forwarding on your server, that would receive a HTTPS request from your code and send a HTTP-request to API.
I would suggest first try to run from a localhost or local file(not sure if every browser will allow AJAX from a local file, but you can try before setting up localhost), that should work for you. If you just want to test the API you can simple copy the URL of the GET-request into you browser tab and execute it.
I want to capture the HTTP request header fields, primarily the Referer and User-Agent, within my client-side JavaScript. How may I access them?
Google Analytics manages to get the data via JavaScript that they have you embed in you pages, so it is definitely possible.
Related:
Accessing the web page's HTTP Headers in JavaScript
If you want to access referrer and user-agent, those are available to client-side Javascript, but not by accessing the headers directly.
To retrieve the referrer, use document.referrer.
To access the user-agent, use navigator.userAgent.
As others have indicated, the HTTP headers are not available, but you specifically asked about the referer and user-agent, which are available via Javascript.
Almost by definition, the client-side JavaScript is not at the receiving end of a http request, so it has no headers to read. Most commonly, your JavaScript is the result of an http response. If you are trying to get the values of the http request that generated your response, you'll have to write server side code to embed those values in the JavaScript you produce.
It gets a little tricky to have server-side code generate client side code, so be sure that is what you need. For instance, if you want the User-agent information, you might find it sufficient to get the various values that JavaScript provides for browser detection. Start with navigator.appName and navigator.appVersion.
This can be accessed through Javascript because it's a property of the loaded document, not of its parent.
Here's a quick example:
<script type="text/javascript">
document.write(document.referrer);
</script>
The same thing in PHP would be:
<?php echo $_SERVER["HTTP_REFERER"]; ?>
Referer and user-agent are request header, not response header.
That means they are sent by browser, or your ajax call (which you can modify the value), and they are decided before you get HTTP response.
So basically you are not asking for a HTTP header, but a browser setting.
The value you get from document.referer and navigator.userAgent may not be the actual header, but a setting of browser.
One way to obtain the headers from JavaScript is using the WebRequest API, which allows us to access the different events that originate from http or websockets, the life cycle that follows is this:
WebRequest Lifecycle
So in order to access the headers of a page it would be like this:
browser.webRequest.onHeadersReceived.addListener(
(headersDetails)=> {
console.log("Request: " + headersDetails);
},
{urls: ["*://hostName/*"]}
);`
The issue is that in order to use this API, it must be executed from the browser, that is, the browser object refers to the browser itself (tabs, icons, configuration), and the browser does have access to all the Request and Reponse of any page , so you will have to ask the user for permissions to be able to do this (The permissions will have to be declared in the manifest for the browser to execute them)
And also being part of the browser you lose control over the pages, that is, you can no longer manipulate the DOM, (not directly) so to control the DOM again it would be done as follows:
browser.webRequest.onHeadersReceived.addListener(
browser.tabs.executeScript({
code: 'console.log("Headers success")',
});
});
or if you want to run a lot of code
browser.webRequest.onHeadersReceived.addListener(
browser.tabs.executeScript({
file: './headersReveiced.js',
});
});
Also by having control over the browser we can inject CSS and images
Documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
I would imagine Google grabs some data server-side - remember, when a page loads into your browser that has Google Analytics code within it, your browser makes a request to Google's servers; Google can obtain data in that way as well as through the JavaScript embedded in the page.
var ref = Request.ServerVariables("HTTP_REFERER");
Type within the quotes any other server variable name you want.
I have found this very useful Chrome extension called Postman. This is a very useful extension especially when you are into programming RESTful applications.
One thing I am confused on is that how this plugin/extension able to send POST request successfully on different domains?
I tried voting in a poll using Postman like this.
After submitting that, the vote was actually counted in, but when I tried doing that using AJAX and JavaScript, it fails, because of different origin policy of browsers.
How is that even possible?
Here is my code using jQuery. I used that in my computer though, localhost.
init: function() {
$.ajax({
url: 'http://example.com/vote.php',
type:'POST',
dataType: 'html',
data: {
id: '1'
},
success: function(data) {
if ( data == 'voted' ) {
$('.set-result').html( 'you already voted. try again after 24 hours' );
} else {
$('.set-result').html( 'successfully voted' );
}
}
});
},
Chrome packaged apps can have cross domain permissions. When you install Postman it promts you that this app will access any domain.
By placing */* in permissions section of your manifest file, you can do this.
Read more here:
https://developer.chrome.com/extensions/xhr.html
You can add the following header to sent Ajax request in postman.
Content-Type application/json
X-Requested-With XMLHttpRequest
Screenshot
Sounds like the site that hosts the poll (the "vote.php" script) needs to have an "Access-Control-Allow-Origin" header set to allow posting from a list of sites (or all sites).
A value of * for the header will allow posting from any website:
Access-Control-Allow-Origin: *
i.e. You could put the following at the top of vote.php
header('Access-Control-Allow-Origin: *');
Chrome extensions and apps are not subject to the same security limitations placed on normal webpages.
Additional debugging tips:
If you're trying to access remote services from web pages you have open on your local file system in your browser, you might find your browser applies different security rules to them than it does to files served from a web service.
e.g. If you open local files from a locational like C:\MyDocuments\weboot\index.htm (Windows) or \Users\joe\Sites\index.html (Mac) in your browser your AJAX request might not work, even with the header specified in most browsers.
Apple's Safari applies almost no cross domain restrictions to files opened locally but Firefox is much more strict about what it permits, with Chrome somewhere in the middle. Running a web server locally (e.g. on http://localhost/) is a good idea to avoid unexpected behaviour.
Additionally, other libraries that provide functions to handle Ajax requests (such as AngularJS) may require other headers to be set on the server by default. You can usually see the reason for failure in a browser debug console.
2021 Oct
In my investigation, I found out that you need an extra field in the header of your request. So simply add the following key-value into the header:
key: X-Requested-With | value: XMLHttpRequest
I want to capture the HTTP request header fields, primarily the Referer and User-Agent, within my client-side JavaScript. How may I access them?
Google Analytics manages to get the data via JavaScript that they have you embed in you pages, so it is definitely possible.
Related:
Accessing the web page's HTTP Headers in JavaScript
If you want to access referrer and user-agent, those are available to client-side Javascript, but not by accessing the headers directly.
To retrieve the referrer, use document.referrer.
To access the user-agent, use navigator.userAgent.
As others have indicated, the HTTP headers are not available, but you specifically asked about the referer and user-agent, which are available via Javascript.
Almost by definition, the client-side JavaScript is not at the receiving end of a http request, so it has no headers to read. Most commonly, your JavaScript is the result of an http response. If you are trying to get the values of the http request that generated your response, you'll have to write server side code to embed those values in the JavaScript you produce.
It gets a little tricky to have server-side code generate client side code, so be sure that is what you need. For instance, if you want the User-agent information, you might find it sufficient to get the various values that JavaScript provides for browser detection. Start with navigator.appName and navigator.appVersion.
This can be accessed through Javascript because it's a property of the loaded document, not of its parent.
Here's a quick example:
<script type="text/javascript">
document.write(document.referrer);
</script>
The same thing in PHP would be:
<?php echo $_SERVER["HTTP_REFERER"]; ?>
Referer and user-agent are request header, not response header.
That means they are sent by browser, or your ajax call (which you can modify the value), and they are decided before you get HTTP response.
So basically you are not asking for a HTTP header, but a browser setting.
The value you get from document.referer and navigator.userAgent may not be the actual header, but a setting of browser.
One way to obtain the headers from JavaScript is using the WebRequest API, which allows us to access the different events that originate from http or websockets, the life cycle that follows is this:
WebRequest Lifecycle
So in order to access the headers of a page it would be like this:
browser.webRequest.onHeadersReceived.addListener(
(headersDetails)=> {
console.log("Request: " + headersDetails);
},
{urls: ["*://hostName/*"]}
);`
The issue is that in order to use this API, it must be executed from the browser, that is, the browser object refers to the browser itself (tabs, icons, configuration), and the browser does have access to all the Request and Reponse of any page , so you will have to ask the user for permissions to be able to do this (The permissions will have to be declared in the manifest for the browser to execute them)
And also being part of the browser you lose control over the pages, that is, you can no longer manipulate the DOM, (not directly) so to control the DOM again it would be done as follows:
browser.webRequest.onHeadersReceived.addListener(
browser.tabs.executeScript({
code: 'console.log("Headers success")',
});
});
or if you want to run a lot of code
browser.webRequest.onHeadersReceived.addListener(
browser.tabs.executeScript({
file: './headersReveiced.js',
});
});
Also by having control over the browser we can inject CSS and images
Documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
I would imagine Google grabs some data server-side - remember, when a page loads into your browser that has Google Analytics code within it, your browser makes a request to Google's servers; Google can obtain data in that way as well as through the JavaScript embedded in the page.
var ref = Request.ServerVariables("HTTP_REFERER");
Type within the quotes any other server variable name you want.
On an HTML page, while clicking the link of an Image ("img") or anchor ("a") tags, I would like to add custom headers for the GET request. These links are typically for downloading dynamic content. These headers could be SAML headers or custom application specific headers.
Is it possible to add these custom headers through JavaScript? Or if I add these through XMLHttpRequest, how can I achieve the download functionality?
This requirement is for IE6 or 7 only.
If you're using XHR, then setRequestHeader should work, e.g.
xhr.setRequestHeader('custom-header', 'value');
P.S. You should use Hijax to modify the behavior of your anchors so that it works if for some reason the AJAX isn't working for your clients (like a busted script elsewhere on the page).
I think the easiest way to accomplish it is to use querystring instead of HTTP headers.
The only way to add headers to a request from inside a browser is use the XmlHttpRequest setRequestHeader method.
Using this with "GET" request will download the resource. The trick then is to access the resource in the intended way. Ostensibly you should be able to allow the GET response to be cacheable for a short period, hence navigation to a new URL or the creation of an IMG tag with a src url should use the cached response from the previous "GET". However that is quite likely to fail especially in IE which can be a bit of a law unto itself where the cache is concerned.
Ultimately I agree with Mehrdad, use of query string is easiest and most reliable method.
Another quirky alternative is use an XHR to make a request to a URL that indicates your intent to access a resource. It could respond with a session cookie which will be carried by the subsequent request for the image or link.
In 2021, this can be accomplished with Service Workers.
First, you have to register a Service Worker on your page.
// index.html
window.addEventListener('load', function () {
navigator
.serviceWorker
.register('/service-worker.js');
});
In the Service Worker a request is captured, modified and forwarded by calling the WindowOrWorkerGlobalScope.fetch() method.
// service-worker.js
self.addEventListener('fetch', function (event) {
event.respondWith(async function () {
let headers = new Headers()
headers.append("X-Custom-Header", "Random value")
return fetch(event.request, {headers: headers})
}());
});
Please note that some web browsers do not show modified requests in the developer console. In that case requests can be observed with tools like tcpdump, Wireshark or in a server's logs.