Check if third-party cookies are enabled - javascript

I have an application that needs to check whether the client browser has third-party-cookies enabled. Does anyone know how to do this in JavaScript?

Technical Background
The third party sets & reads cookies over HTTP (not in JavaScript).
So we need two requests to an external domain to test if third-party cookies are enabled:
One where the third party sets the cookie(s)
The second, with a differing response depending on whether the browser sent the cookie(s) back to the same third party in a second request.
We cannot use XMLHTTPRequest (Ajax) because of the DOM security model.
Obviously you can't load both scripts in parallel, or the second request may be made before the first request’s response makes it back, and the test cookie(s) will not have been set.
Code Example
Given:
The .html file is on one domain, and
The .js.php files are on a second domain, we have:
The HTML test page
Saved as third-party-cookies.html
<!DOCTYPE html>
<html>
<head id="head">
<meta charset=utf-8 />
<title>Test if Third-Party Cookies are Enabled</title>
<style type="text/css">
body {
color: black;
background: white none;
}
.error {
color: #c00;
}
.loading {
color: #888;
}
.hidden {
display: none;
}
</style>
<script type="text/javascript">
window._3rd_party_test_step1_loaded = function(){
// At this point, a third-party domain has now attempted to set a cookie (if all went to plan!)
var step2Url = 'http://third-party.example.com/step2.js.php',
resultsEl = document.getElementById('3rd_party_cookie_test_results'),
step2El = document.createElement('script');
// Update loading / results message
resultsEl.innerHTML = 'Stage one complete, loading stage 2…';
// And load the second part of the test (reading the cookie)
step2El.setAttribute('src', step2Url);
resultsEl.appendChild(step2El);
}
window._3rd_party_test_step2_loaded = function(cookieSuccess){
var resultsEl = document.getElementById('3rd_party_cookie_test_results'),
errorEl = document.getElementById('3rd_party_cookie_test_error');
// Show message
resultsEl.innerHTML = (cookieSuccess ? 'Third party cookies are <b>functioning</b> in your browser.' : 'Third party cookies appear to be <b>disabled</b>.');
// Done, so remove loading class
resultsEl.className = resultsEl.className.replace(/\bloading\b/,' ');
// And remove error message
errorEl.className = 'hidden';
}
</script>
</head>
<body id="thebody">
<h1>Test if Third-Party Cookies are Enabled</h1>
<p id="3rd_party_cookie_test_results" class='loading'>Testing…</p>
<p id="3rd_party_cookie_test_error" class="error hidden">(If this message persists, the test could not be completed; we could not reach the third-party to test, or another error occurred.)</p>
<script type="text/javascript">
window.setTimeout(function(){
var errorEl = document.getElementById('3rd_party_cookie_test_error');
if(errorEl.className.match(/\berror\b/)) {
// Show error message
errorEl.className = errorEl.className.replace(/\bhidden\b/,' ');
} else {
}
}, 7*1000); // 7 sec timeout
</script>
<script type="text/javascript" src="http://third-party.example.com/step1.js.php"></script>
</body>
</html>
The first third-party JavaScript file
Saved as step1.js.php
This is written in PHP so we can set cookies as the file loads. (It could, of course, be written in any language, or even done in server config files.)
<?php
header('Content-Type: application/javascript; charset=UTF-8');
// Set test cookie
setcookie('third_party_c_t', 'hey there!', time() + 3600*24*2);
?>
window._3rd_party_test_step1_loaded();
The second third-party JavaScript file
Saved as step2.js.php
This is written in PHP so we can read cookies, server-side, before we respond. We also clear the cookie so the test can be repeated (if you want to mess around with browser settings and re-try).
<?php
header('Content-Type: application/javascript; charset=UTF-8');
// Read test cookie, if there
$cookie_received = (isset($_COOKIE['third_party_c_t']) && $_COOKIE['third_party_c_t'] == 'hey there!');
// And clear it so the user can test it again
setcookie('third_party_c_t', '', time() - 3600*24);
?>
window._3rd_party_test_step2_loaded(<?php echo ($cookie_received ? 'true' : 'false'); ?>);
The last line uses the ternary operator to output a literal Javascript true or false depending on whether the test cookie was present.
Test it here.
Available for your testing pleasure at https://alanhogan.github.io/web-experiments/3rd/third-party-cookies.html.
(As a final note — don’t use someone else’s server to test third-party cookies without their permission. It could break spontaneously or inject malware. And it’s rude.)

Here's a pure JS solution not requiring any server-side code, so it can work from a static CDN: https://github.com/mindmup/3rdpartycookiecheck - the first script sets the cookie in the code, then redirects to a second script that will post a message to the parent window.
You can try out a live version using https://jsfiddle.net/tugawg8y/.
Note, this demo does not seem to work any more. Maybe the window.postMessage call is being blocked.
client-side HTML:
third party cookies are <span id="result"/>
<iframe src="https://mindmup.github.io/3rdpartycookiecheck/start.html"
style="display:none" />
client-side JS:
var receiveMessage = function (evt) {
if (evt.data === 'MM:3PCunsupported') {
document.getElementById('result').innerHTML = 'not supported';
} else if (evt.data === 'MM:3PCsupported') {
document.getElementById('result').innerHTML = 'supported';
}
};
window.addEventListener("message", receiveMessage, false);
Of course, this requires that the client runs JavaScript which is a downside compared to the server-based solutions; on the other hand, it's simpler, and you were asking about a JS solution.

Alan H's solution is great, but you don't have to use PHP or any other server-side programming language.
At least if you use nginx. :)
This is a pure* nginx server-side configuration for Alan's solution:
server {
listen 80;
server_name third-party.example.com
# Don't allow user's browser to cache these replies
expires -1;
add_header Cache-Control "private";
etag off;
# The first third-party "JavaScript file" - served by nginx
location = /step1.js.php {
add_header Content-Type 'application/javascript; charset=UTF-8';
add_header Set-Cookie "third_party_c_t=hey there!;Max-Age=172800";
return 200 'window._3rd_party_test_step1_loaded();';
}
# The second third-party "JavaScript file" - served by nginx
location = /step2.js.php {
add_header Content-Type 'application/javascript; charset=UTF-8';
set $test 'false';
if ($cookie_third_party_c_t = 'hey there!') {
set $test 'true';
# clear the cookie
add_header Set-Cookie "third_party_c_t=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
return 200 'window._3rd_party_test_step2_loaded($test);';
}
}
Side notes:
Yeah, yeah, I know that IfIsEvil,
I kept the names ending with ".php" for complete compatibility with Alan's "The HTML test page" (third-party-cookies.html),
You can also move the common "setting the Content-Type header" line of both locations to the server section (scope) of the config - I kept it like this to make it more like Alan H's solution.

My solution works by loading a <script> from an external domain that sets a cookie, checks if it was successful, and then passes the result (1 or 0) as an argument to a callback function.
The HTML:
<script>
function myCallback(is_enabled) {
if (is_enabled===1) {//third party cookies are enabled
}
}
</script>
<script src="https://third-party-domain/third-party-cookies.php?callback=myCallback"></script>
If you prefer to run it asynchronously, you may use the async and defer attributes.
This also works with jQuery:
<script>
$.ajax({
url: 'https://third-party-domain/third-party-cookies.php',
dataType: 'jsonp',
}).done(function(is_enabled) {
if (is_enabled===1) {//third party cookies are enabled
}
})
</script>
Here is the third-party-cookies.php code. This must be hosted on a different domain. The server must support PHP:
<?php
header('Cache-Control: no-store');
header('Content-Type: text/javascript');
if ($_GET['callback']=='') {
echo 'alert("Error: A callback function must be specified.")';
}
elseif (!isset($_GET['cookieName'])) {// Cookie not set yet
$cookieName = strtr((string)$_SERVER['UNIQUE_ID'], '#', '_');
while (isset($_COOKIE[$cookieName]) || $cookieName=='') {
$cookieName = dechex(mt_rand());// Get random cookie name
}
setcookie($cookieName, '3rd-party', 0, '/');
header('Location: '.$_SERVER['REQUEST_URI'].'&cookieName='.$cookieName);
}
elseif ($_COOKIE[$_GET['cookieName']]=='3rd-party') {// Third party cookies are enabled.
setcookie($_GET['cookieName'], '', -1, '/'); // delete cookie
echo $_GET['callback'].'(1)';
}
else {// Third party cookies are not enabled.
echo $_GET['callback'].'(0)';
}

In theory you'd just have a page call out somewhere that would set a thirdparty cookie and then check for that cookie's existence. However, standard browser security does not allow scripts from domain A to do anything with cookies set on domains B,C,etc... e.g. you can't access "foreign" cookies.
If you have some specific usage in mind, such as checking if ads are blocked (which would also block the 3rd party tracking cookie), you could check if the ad server's content is within the page's DOM, but you couldn't see if the cookie's there.

Third Party Cookie detection with Whitelisting of URLs
Alan H & Gojko Adzic are good enough for majority of use cases, but these solutions won't work if you want your users to do whitelisting of third party cookies only to certain domains.
I'm presenting a slightly modified version of Gojko Adzic's answer
For this we need two domains :
Domain 1, this is the page your user lands, it initially sets tpc=pending, then it redirects to Domain 2
Domain 2 injects Domain 1's url in an iFrame, tries to set a cookie tpc=true and redirects back to Domain 1
Now, Domain 1 reads the cookie tpc and checks if its true, if we get value as true, third party cookies are allowed if it is still in pending third party cookies are blocked blocked.
Now, you might ask your users to whitelist (allow third party cookies) ONLY for Domain 1, also by this technique third party detection will be accurate if the users had white listed your domain.
This is tested in Chrome 74, 75, 76 & Edge 78
Unfortunately, Mozilla doesn't provide whitelisting of urls like Chrome does and Safari has it own mechanisms of detecting third party cookies (ITP).
P.S. Will upload this demo in my github when I get time.

This is something that I did to check if third-parties cookies have been blocked by the user.
I just try to access the browser's local storage. If the user has enabled third-party cookies then it should be available, else it would throw an error.
try {
if(window.localStorage) {
//cookies enabled
}
} catch (err) {
//cookies disabled
}

Steps to check if third party cookies are enabled with Greg and Alan's solutions:
I modify the files as my only need was to check if third party cookies are enabled or not, depends on that i would do something like route them to a page telling users to enable third party cookies.
1) Edit your nginx sites config
(In debian 9 is in /etc/nginx/sites-enabled/default)
$ sudo nano /etc/nginx/sites-enabled/default
You'll need to have TLS/SSL on your domain or else you won't be able to set cookies from a third party domain and you'll get an error saying:
Because a cookie’s SameSite attribute was not set or is invalid, it defaults to SameSite=Lax, which prevents the cookie from being sent in a cross-site request. This behavior protects user data from accidentally leaking to third parties and cross-site request forgery. Resolve this issue by updating the attributes of the cookie: Specify SameSite=None and Secure if the cookie should be sent in cross-site requests. This enables third-party use. Specify SameSite=Strict or SameSite=Lax if the cookie should not be sent in cross-site requests.
Specify your allowed domains in "Access-Control-Allow-Origin", not recomended to leave it with "*" (public access).
You can specify 'Access-Control-Allow-Methods "GET";' as is the only method being used.
(I set those headers with "*" (public) just to make sure it works, after that, you can edit them.)
You can change the name of the endpoints (step1.js.php & step2.js.php) but you'll need to change it in you js script. (Requests are made to your-custom-domain.com/step1.js.php o your-custom-domain.com/step2.js.php unless you change it. The extension does not really matter, you can change it for "step1" and "step2" or whatever you like)
# Nginx config start
server {
server_name your-custom-domain.com;
# Check if third party cookies are allowed
# The first third-party "JavaScript file" - served by nginx
location = /step1.js.php {
expires -1;
add_header Cache-Control "private";
etag off;
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "*";
add_header Content-Type 'application/javascript; charset=UTF-8';
add_header Set-Cookie "third_party_c_t=hey there!;Max-Age=172000; Secure; SameSite=none";
return 200 'window._3rd_party_test_step1_loaded();';
}
# The second third-party "JavaScript file" - served by nginx
location = /step2.js.php {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "*";
add_header Content-Type 'application/javascript; charset=UTF-8';
set $test 'false';
if ($cookie_third_party_c_t = 'hey there!') {
set $test 'true';
# clear the cookie
add_header Set-Cookie "third_party_c_t=;expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; SameSite=none";
}
return 200 'window._3rd_party_test_step2_loaded($test);';
}
# managed by Certbot, here is where your certificates goes.
listen [::]:443 ssl ipv6only=on;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.couchdb.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.couchdb.me/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
Save it (ctrl+x - Press letter Y if you want to save it - Enter to confirm) and restart/reload your nginx:
$ sudo systemctl restart nginx.service
2) In your landing page (different from your-custom-domain.com)
You can change the name of the methods (_3rd_party_test_step1_loaded and _3rd_party_test_step2_loaded) but you'll need to change it also in nginx's config. (Make sure names are unique)
2.1) Add this cript to the header of your html (this must be loaded first):
<script type="text/javascript">
window._3rd_party_test_step1_loaded = function () {
// At this point, a third-party domain has now attempted to set a cookie (if all went to plan!)
var step2El = document.createElement("script");
const url = your-custom-domain.com + "/step2.js.php";
step2El.setAttribute("src", url);
document.head.appendChild(step2El);
};
window._3rd_party_test_step2_loaded = function (cookieSuccess) {
// If true, the third-party domain cookies are enabled
// If false, the third-party domain cookies are disable
cookieSuccess ? callMethodIfTrue() : callMethodIfFalse();
};
</script>
2.2) Add the script at the end of your body html:
<script type="text/javascript" src="https://your-custom-domain/step1.js.php"></script>
or if your are working in a js file (remember that you need to have your file added on your html landing page eg:
<script type="text/javascript" src="path/to/your/js/file"></script>
JS file:
window._3rd_party_test_step1_loaded = function () {
// At this point, a third-party domain has now attempted to set a cookie (if all went to plan!)
var step2El = document.createElement("script");
const url = that.$url + "/step2.js.php";
step2El.setAttribute("src", url);
document.head.appendChild(step2El);
};
window._3rd_party_test_step2_loaded = function (cookieSuccess) {
// If true, the third-party domain cookies are enabled
// If false, the third-party domain cookies are disable
cookieSuccess ? callMethodIfTrue() : callMethodIfFalse();
};
window.onload = function () {
const url = "your-custom-domain.com" + "/step1.js.php";
var step1El = document.createElement("script");
step1El.setAttribute("src", url);
document.body.appendChild(step1El);
};

Related

Failed posting data with axios [duplicate]

I'm trying to load a cross-domain HTML page using AJAX but unless the dataType is "jsonp" I can't get a response. However using jsonp the browser is expecting a script mime type but is receiving "text/html".
My code for the request is:
$.ajax({
type: "GET",
url: "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute",
dataType: "jsonp",
}).success( function( data ) {
$( 'div.ajax-field' ).html( data );
});
Is there any way of avoiding using jsonp for the request? I've already tried using the crossDomain parameter but it didn't work.
If not is there any way of receiving the html content in jsonp? Currently the console is saying "unexpected <" in the jsonp reply.
jQuery Ajax Notes
Due to browser security restrictions, most Ajax requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, port, or protocol.
Script and JSONP requests are not subject to the same origin policy restrictions.
There are some ways to overcome the cross-domain barrier:
CORS Proxy Alternatives
Ways to circumvent the same-origin policy
Breaking The Cross Domain Barrier
There are some plugins that help with cross-domain requests:
Cross Domain AJAX Request with YQL and jQuery
Cross-domain requests with jQuery.ajax
Heads up!
The best way to overcome this problem, is by creating your own proxy in the back-end, so that your proxy will point to the services in other domains, because in the back-end not exists the same origin policy restriction. But if you can't do that in back-end, then pay attention to the following tips.
**Warning!**
Using third-party proxies is not a secure practice, because they can keep track of your data, so it can be used with public information, but never with private data.
The code examples shown below use jQuery.get() and jQuery.getJSON(), both are shorthand methods of jQuery.ajax()
CORS Anywhere
2021 Update
Public demo server (cors-anywhere.herokuapp.com) will be very limited by January 2021, 31st
The demo server of CORS Anywhere (cors-anywhere.herokuapp.com) is meant to be a demo of this project. But abuse has become so common that the platform where the demo is hosted (Heroku) has asked me to shut down the server, despite efforts to counter the abuse. Downtime becomes increasingly frequent due to abuse and its popularity.
To counter this, I will make the following changes:
The rate limit will decrease from 200 per hour to 50 per hour.
By January 31st, 2021, cors-anywhere.herokuapp.com will stop serving as an open proxy.
From February 1st. 2021, cors-anywhere.herokuapp.com will only serve requests after the visitor has completed a challenge: The user (developer) must visit a page at cors-anywhere.herokuapp.com to temporarily unlock the demo for their browser. This allows developers to try out the functionality, to help with deciding on self-hosting or looking for alternatives.
CORS Anywhere is a node.js proxy which adds CORS headers to the proxied request.
To use the API, just prefix the URL with the API URL. (Supports https: see github repository)
If you want to automatically enable cross-domain requests when needed, use the following snippet:
$.ajaxPrefilter( function (options) {
if (options.crossDomain && jQuery.support.cors) {
var http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
options.url = http + '//cors-anywhere.herokuapp.com/' + options.url;
//options.url = "http://cors.corsproxy.io/url=" + options.url;
}
});
$.get(
'http://en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
Whatever Origin
Whatever Origin is a cross domain jsonp access. This is an open source alternative to anyorigin.com.
To fetch the data from google.com, you can use this snippet:
// It is good specify the charset you expect.
// You can use the charset you want instead of utf-8.
// See details for scriptCharset and contentType options:
// http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
$.ajaxSetup({
scriptCharset: "utf-8", //or "ISO-8859-1"
contentType: "application/json; charset=utf-8"
});
$.getJSON('http://whateverorigin.org/get?url=' +
encodeURIComponent('http://google.com') + '&callback=?',
function (data) {
console.log("> ", data);
//If the expected response is text/plain
$("#viewer").html(data.contents);
//If the expected response is JSON
//var response = $.parseJSON(data.contents);
});
CORS Proxy
CORS Proxy is a simple node.js proxy to enable CORS request for any website.
It allows javascript code on your site to access resources on other domains that would normally be blocked due to the same-origin policy.
CORS-Proxy gr2m (archived)
CORS-Proxy rmadhuram
How does it work?
CORS Proxy takes advantage of Cross-Origin Resource Sharing, which is a feature that was added along with HTML 5. Servers can specify that they want browsers to allow other websites to request resources they host. CORS Proxy is simply an HTTP Proxy that adds a header to responses saying "anyone can request this".
This is another way to achieve the goal (see www.corsproxy.com). All you have to do is strip http:// and www. from the URL being proxied, and prepend the URL with www.corsproxy.com/
$.get(
'http://www.corsproxy.com/' +
'en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
The http://www.corsproxy.com/ domain now appears to be an unsafe/suspicious site. NOT RECOMMENDED TO USE.
CORS proxy browser
Recently I found this one, it involves various security oriented Cross Origin Remote Sharing utilities. But it is a black-box with Flash as backend.
You can see it in action here: CORS proxy browser
Get the source code on GitHub: koto/cors-proxy-browser
You can use Ajax-cross-origin a jQuery plugin.
With this plugin you use jQuery.ajax() cross domain. It uses Google services to achieve this:
The AJAX Cross Origin plugin use Google Apps Script as a proxy jSON
getter where jSONP is not implemented. When you set the crossOrigin
option to true, the plugin replace the original url with the Google
Apps Script address and send it as encoded url parameter. The Google
Apps Script use Google Servers resources to get the remote data, and
return it back to the client as JSONP.
It is very simple to use:
$.ajax({
crossOrigin: true,
url: url,
success: function(data) {
console.log(data);
}
});
You can read more here:
http://www.ajax-cross-origin.com/
If the external site doesn't support JSONP or CORS, your only option is to use a proxy.
Build a script on your server that requests that content, then use jQuery ajax to hit the script on your server.
Just put this in the header of your PHP Page and it ill work without API:
header('Access-Control-Allow-Origin: *'); //allow everybody
or
header('Access-Control-Allow-Origin: http://codesheet.org'); //allow just one domain
or
$http_origin = $_SERVER['HTTP_ORIGIN']; //allow multiple domains
$allowed_domains = array(
'http://codesheet.org',
'http://stackoverflow.com'
);
if (in_array($http_origin, $allowed_domains))
{
header("Access-Control-Allow-Origin: $http_origin");
}
I'm posting this in case someone faces the same problem I am facing right now. I've got a Zebra thermal printer, equipped with the ZebraNet print server, which offers a HTML-based user interface for editing multiple settings, seeing the printer's current status, etc. I need to get the status of the printer, which is displayed in one of those html pages, offered by the ZebraNet server and, for example, alert() a message to the user in the browser. This means that I have to get that html page in Javascript first. Although the printer is within the LAN of the user's PC, that Same Origin Policy is still staying firmly in my way. I tried JSONP, but the server returns html and I haven't found a way to modify its functionality (if I could, I would have already set the magic header Access-control-allow-origin: *). So I decided to write a small console app in C#. It has to be run as Admin to work properly, otherwise it trolls :D an exception. Here is some code:
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
//foreach (string s in prefixes)
//{
// listener.Prefixes.Add(s);
//}
listener.Prefixes.Add("http://*:1234/"); // accept connections from everywhere,
//because the printer is accessible only within the LAN (no portforwarding)
listener.Start();
Console.WriteLine("Listening...");
// Note: The GetContext method blocks while waiting for a request.
HttpListenerContext context;
string urlForRequest = "";
HttpWebRequest requestForPage = null;
HttpWebResponse responseForPage = null;
string responseForPageAsString = "";
while (true)
{
context = listener.GetContext();
HttpListenerRequest request = context.Request;
urlForRequest = request.RawUrl.Substring(1, request.RawUrl.Length - 1); // remove the slash, which separates the portNumber from the arg sent
Console.WriteLine(urlForRequest);
//Request for the html page:
requestForPage = (HttpWebRequest)WebRequest.Create(urlForRequest);
responseForPage = (HttpWebResponse)requestForPage.GetResponse();
responseForPageAsString = new StreamReader(responseForPage.GetResponseStream()).ReadToEnd();
// Obtain a response object.
HttpListenerResponse response = context.Response;
// Send back the response.
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseForPageAsString);
// Get a response stream and write the response to it.
response.ContentLength64 = buffer.Length;
response.AddHeader("Access-Control-Allow-Origin", "*"); // the magic header in action ;-D
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
//listener.Stop();
All the user needs to do is run that console app as Admin. I know it is way too ... frustrating and complicated, but it is sort of a workaround to the Domain Policy problem in case you cannot modify the server in any way.
edit: from js I make a simple ajax call:
$.ajax({
type: 'POST',
url: 'http://LAN_IP:1234/http://google.com',
success: function (data) {
console.log("Success: " + data);
},
error: function (e) {
alert("Error: " + e);
console.log("Error: " + e);
}
});
The html of the requested page is returned and stored in the data variable.
To get the data form external site by passing using a local proxy as suggested by jherax you can create a php page that fetches the content for you from respective external url and than send a get request to that php page.
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost/get_url_content.php',false);
if(req.status == 200) {
alert(req.responseText);
}
as a php proxy you can use https://github.com/cowboy/php-simple-proxy
Your URL doesn't work these days, but your code can be updated with this working solution:
var url = "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute";
url = 'https://google.com'; // TEST URL
$.get("https://images"+~~(Math.random()*33)+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURI(url), function(data) {
$('div.ajax-field').html(data);
});
<div class="ajax-field"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You need CORS proxy which proxies your request from your browser to requested service with appropriate CORS headers. List of such services are in code snippet below. You can also run provided code snippet to see ping to such services from your location.
$('li').each(function() {
var self = this;
ping($(this).text()).then(function(delta) {
console.log($(self).text(), delta, ' ms');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/jdfreder/pingjs/c2190a3649759f2bd8569a72ae2b597b2546c871/ping.js"></script>
<ul>
<li>https://crossorigin.me/</li>
<li>https://cors-anywhere.herokuapp.com/</li>
<li>http://cors.io/</li>
<li>https://cors.5apps.com/?uri=</li>
<li>http://whateverorigin.org/get?url=</li>
<li>https://anyorigin.com/get?url=</li>
<li>http://corsproxy.nodester.com/?src=</li>
<li>https://jsonp.afeld.me/?url=</li>
<li>http://benalman.com/code/projects/php-simple-proxy/ba-simple-proxy.php?url=</li>
</ul>
Figured it out.
Used this instead.
$('.div_class').load('http://en.wikipedia.org/wiki/Cross-origin_resource_sharing #toctitle');

I have multiple domains, is there any way for them to share the same cookie [duplicate]

I have two webapps WebApp1 and WebApp2 in two different domains.
I am setting a cookie in WebApp1 in the HttpResponse.
How to read the same cookie from HttpRequest in WebApp2?
I know it sounds weird because cookies are specific to a given domain, and we can't access them from different domains; I've however heard of CROSS-DOMAIN cookies which can be shared across multiple webapps. How to implement this requirement using CROSS-DOMAIN cookies?
Note: I am trying this with J2EE webapps
Yes, it is absolutely possible to get the cookie from domain1.example by domain2.example. I had the same problem for a social plugin of my social network, and after a day of research I found the solution.
First, on the server side you need to have the following headers:
header("Access-Control-Allow-Origin: http://origin.domain:port");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: Content-Type, *");
Within the PHP-file you can use $_COOKIE[name]
Second, on the client side:
Within your AJAX request you need to include 2 parameters
crossDomain: true
xhrFields: { withCredentials: true }
Example:
type: "get",
url: link,
crossDomain: true,
dataType: 'json',
xhrFields: {
withCredentials: true
}
As other people say, you cannot share cookies, but you could do something like this:
centralize all cookies in a single domain, let's say cookiemaker.example
when the user makes a request to example.com you redirect him to cookiemaker.example
cookiemaker.example redirects him back to example.com with the information you need
Of course, it's not completely secure, and you have to create some kind of internal protocol between your apps to do that.
Lastly, it would be very annoying for the user if you do something like that in every request, but not if it's just the first.
But I think there is no other way.
As far as I know, cookies are limited by the "same origin" policy. However, with CORS you can receive and use the "Server B" cookies to establish a persistent session from "Server A" on "Server B".
Although, this requires some headers on "Server B":
Access-Control-Allow-Origin: http://server-a.example.com
Access-Control-Allow-Credentials: true
And you will need to send the flag "withCredentials" on all the "Server A" requests (ex: xhr.withCredentials = true;)
You can read about it here:
http://www.html5rocks.com/en/tutorials/cors/
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
There's no such thing as cross domain cookies. You could share a cookie between foo.example.com and bar.example.com but never between example.com and example2.com and that's for security reasons.
The smartest solution is to follow facebook's path on this. How does facebook know who you are when you visit any domain? It's actually very simple:
The Like button actually allows Facebook to track all visitors of the external site, no matter if they click it or not. Facebook can do that because they use an iframe to display the button. An iframe is something like an embedded browser window within a page. The difference between using an iframe and a simple image for the button is that the iframe contains a complete web page – from Facebook. There is not much going on on this page, except for the button and the information about how many people have liked the current page.
So when you see a like button on cnn.com, you are actually visiting a Facebook page at the same time. That allows Facebook to read a cookie on your computer, which it has created the last time you’ve logged in to Facebook.
A fundamental security rule in every browser is that only the website that has created a cookie can read it later on. And that is the advantage of the iframe: it allows Facebook to read your Facebook-cookie even when you are visiting a different website. That’s how they recognize you on cnn.com and display your friends there.
Source:
http://dorianroy.com/blog/2010/04/how-facebooks-like-button-works/
https://stackoverflow.com/a/8256920/715483
Cross-domain cookies are not allowed (i.e. site A cannot set a cookie on site B).
But once a cookie is set by site A, you can send that cookie even in requests from site B to site A (i.e. cross-domain requests):
XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request. The third-party cookies obtained by setting withCredentials to true will still honor same-origin policy and hence can not be accessed by the requesting script through document.cookie or from response headers.
Make sure to do these things:
When setting the cookie in a response
The Set-Cookie response header includes SameSite=None if the requests are cross-site (note a request from www.example.dev to static.example.dev is actually a same-site request, and can use SameSite=Strict)
The Set-Cookie response header should include the Secure attribute if served over HTTPS; as seen here and here
When sending/receiving the cookie:
The request is made with withCredentials: true, as mentioned in other answers here and here, including the original request whose response sets the cookie set in the first place
For the fetch API, this attribute is credentials: 'include', vs withCredentials: true
For jQuery's ajax method, note you may need to supply argument crossDomain: true
The server response includes cross-origin headers like Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, and Access-Control-Allow-Methods
As #nabrown points out: "Note that the "Access-Control-Allow-Origin" cannot be the wildcard (*) value if you use the withCredentials: true" (see #nabrown's comment which explains one workaround for this.
In general:
Your browser hasn't disabled 3rd-party cookies. (* see below)
Things that you don't need (just use the above):
domain attribute in the Set-Cookie; you can choose a root domain (i.e. a.example.com can set a cookie with a domain value of example.com, but it's not necessary; the cookie will still be sent to a.example.com, even if sent from b.other-site.example
For the cookie to be visible in Chrome Dev Tools, "Application" tab; if the value of cookie HttpOnly attribute is true, Chrome won't show you the cookie value in the Application tab (it should show the cookie value when set in the initial request, and sent in subsequent responses where withCredentials: true)
Notice the difference between "path" and "site" for Cookie purposes. "path" is not security-related; "site" is security-related:
path
Servers can set a Path attribute in the Set-Cookie, but it doesn't seem security related:
Note that path was intended for performance, not security. Web pages having the same origin still can access cookie via document.cookie even though the paths are mismatched.
site
The SameSite attribute, according to example.dev article, can restrict or allow cross-site cookies; but what is a "site"?
It's helpful to understand exactly what 'site' means here. The site is the combination of the domain suffix and the part of the domain just before it. For example, the www.example.dev domain is part of the example.dev site...
This means a request to static.example.dev from www.example.dev, is a sameSite request (the only difference in the URLs is in the subdomains).
The public suffix list defines this, so
it's not just top-level domains like .com but also includes services
like github.io
This means a request to your-project.github.io from my-project.github.io, is a a cross-site request (these URLs are at different domains, because github.io is the domain suffix; the domains your-project vs my-project are different; hence different sites)
This means what's to the left of the public suffix; is the subdomain (but the subdomain is a part of the host; see the BONUS reply in this answer)
www is the subdomain in www.example.dev; same site as static.example.dev
your-project is the domain in your-project.github.io; separate site as my-project.github.io
In this URL https://www.example.com:8888/examples/index.html, remember these parts:
the "protocol": https://
the "scheme": https
the "port": 8888
the "domain name" aka location.hostname: www.example.com
the "domain suffix" aka "top-level domain" (TLD): com
the "domain": example
the "subdomain": www (the subdomain could be single-level (like www) or multi-level (like foo.bar in foo.bar.example.com)
the "site" (as in "cross-site" if another URL had a different "site" value): example.com
"site" = "domain" + "domain suffix" = example.com
the "path": /examples/index.html
Useful links:
Anatomy of a URL
Same-Origin cookie policy and URL anatomy
SameSite cookies explained
Secure cross-domain cookies for HTTP | Journal of Internet Services and Applications | Full Text
draft-ietf-httpbis-rfc6265bis-03
Web Security 1: Same-Origin and Cookie Policy
Set-Cookie - HTTP | MDN
(Be careful; I was testing my feature in Chrome Incognito tab; according to my chrome://settings/cookies; my settings were "Block third party cookies in Incognito", so I can't test Cross-site cookies in Incognito.)
You cannot share cookies across domains. You can however allow all subdomains to have access. To allow all subdomains of example.com to have access, set the domain to .example.com.
It's not possible giving other.example access to example.com's cookies though.
Do what Google is doing. Create a PHP file that sets the cookie on all 3 domains. Then on the domain where the theme is going to set, create a HTML file that would load the PHP file that sets cookie on the other 2 domains. Example:
<html>
<head></head>
<body>
<p>Please wait.....</p>
<img src="http://domain2.example/setcookie.php?theme=whateveryourthemehere" />
<img src="http://domain3.example/setcookie.php?theme=whateveryourthemehere" />
</body>
</html>
Then add an onload callback on body tag. The document will only load when the images completely load that is when cookies are set on the other 2 domains. Onload Callback:
<head>
<script>
function loadComplete(){
window.location="http://domain1.example";//URL of domain1
}
</script>
</head>
<body onload="loadComplete()">
setcookie.php
We set the cookies on the other domains using a PHP file like this:
<?php
if(isset($_GET['theme'])){
setcookie("theme", $_GET['theme'], time()+3600);
}
?>
Now cookies are set on the three domains.
You can attempt to push the cookie val to another domain using an image tag.
Your mileage may vary when trying to do this because some browsers require you to have a proper P3P Policy on the WebApp2 domain or the browser will reject the cookie.
If you look at plus.google.com p3p policy you will see that their policy is:
CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
that is the policy they use for their +1 buttons to these cross domain requests.
Another warning is that if you are on https make sure that the image tag is pointing to an https address also otherwise the cookies will not set.
There's a decent overview of how Facebook does it here on nfriedly.com
There's also Browser Fingerprinting, which is not the same as a cookie, but serves a like purpose in that it helps you identify a user with a fair degree of certainty. There's a post here on Stack Overflow that references upon one method of fingerprinting
I've created an NPM module, which allows you to share locally-stored data across domains:
https://www.npmjs.com/package/cookie-toss
By using an iframe hosted on Domain A, you can store all of your user data on Domain A, and reference that data by posting requests to the Domain A iframe.
Thus, Domains B, C, etc. can inject the iframe and post requests to it to store and access the desired data. Domain A becomes the hub for all shared data.
With a domain whitelist inside of Domain A, you can ensure only your dependent sites can access the data on Domain A.
The trick is to have the code inside of the iframe on Domain A which is able to recognize which data is being requested. The README in the above NPM module goes more in depth into the procedure.
Hope this helps!
Since it is difficult to do 3rd party cookies and also some browsers won't allow that.
You can try storing them in HTML5 local storage and then sending them with every request from your front end app.
One can use invisible iframes to get the cookies. Let's say there are two domains, a.example and b.example. For the index.html of domain a.example one can add (notice height=0 width=0):
<iframe height="0" id="iframe" src="http://b.example" width="0"></iframe>
That way your website will get b.example cookies assuming that http://b.example sets the cookies.
The next thing would be manipulating the site inside the iframe through JavaScript. The operations inside iframe may become a challenge if one doesn't own the second domain. But in case of having access to both domains referring the right web page at the src of iframe should give the cookies one would like to get.
Along with #Ludovic(approved answer) answers we need to check one more option when getting set-cookies header,
set-cookie: SESSIONID=60B2E91C53B976B444144063; Path=/dev/api/abc; HttpOnly
Check for Path attribute value also. This should be the same as your API starting context path like below
https://www.example.com/dev/api/abc/v1/users/123
or use below value when not sure about context path
Path=/;
function GetOrder(status, filter) {
var isValid = true; //isValidGuid(customerId);
if (isValid) {
var refundhtmlstr = '';
//varsURL = ApiPath + '/api/Orders/Customer/' + customerId + '?status=' + status + '&filter=' + filter;
varsURL = ApiPath + '/api/Orders/Customer?status=' + status + '&filter=' + filter;
$.ajax({
type: "GET",
//url: ApiPath + '/api/Orders/Customer/' + customerId + '?status=' + status + '&filter=' + filter,
url: ApiPath + '/api/Orders/Customer?status=' + status + '&filter=' + filter,
dataType: "json",
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: function (data) {
var htmlStr = '';
if (data == null || data.Count === 0) {
htmlStr = '<div class="card"><div class="card-header">Bu kriterlere uygun sipariş bulunamadı.</div></div>';
}
else {
$('#ReturnPolicyBtnUrl').attr('href', data.ReturnPolicyBtnUrl);
var groupedData = data.OrderDto.sort(function (x, y) {
return new Date(y.OrderDate) - new Date(x.OrderDate);
});
groupedData = _.groupBy(data.OrderDto, function (d) { return toMonthStr(d.OrderDate) });
localStorage['orderData'] = JSON.stringify(data.OrderDto);
$.each(groupedData, function (key, val) {
var sortedData = groupedData[key].sort(function (x, y) {
return new Date(y.OrderDate) - new Date(x.OrderDate);
});
htmlStr += '<div class="card-header">' + key + '</div>';
$.each(sortedData, function (keyitem, valitem) {
//Date Convertions
if (valitem.StatusDesc != null) {
valitem.StatusDesc = valitem.StatusDesc;
}
var date = valitem.OrderDate;
date = date.substring(0, 10).split('-');
date = date[2] + '.' + date[1] + '.' + date[0];
htmlStr += '<div class="col-lg-12 col-md-12 col-xs-12 col-sm-12 card-item clearfix ">' +
//'<div class="card-item-head"><span class="order-head">Sipariş No: <a href="ViewOrderDetails.html?CustomerId=' + customerId + '&OrderNo=' + valitem.OrderNumber + '" >' + valitem.OrderNumber + '</a></span><span class="order-date">' + date + '</span></div>' +
'<div class="card-item-head"><span class="order-head">Sipariş No: <a href="ViewOrderDetails.html?OrderNo=' + valitem.OrderNumber + '" >' + valitem.OrderNumber + '</a></span><span class="order-date">' + date + '</span></div>' +
'<div class="card-item-head-desc">' + valitem.StatusDesc + '</div>' +
'<div class="card-item-body">' +
'<div class="slider responsive">';
var i = 0;
$.each(valitem.ItemList, function (keylineitem, vallineitem) {
var imageUrl = vallineitem.ProductImageUrl.replace('{size}', 200);
htmlStr += '<div><img src="' + imageUrl + '" alt="' + vallineitem.ProductName + '"><span class="img-desc">' + ProductNameStr(vallineitem.ProductName) + '</span></div>';
i++;
});
htmlStr += '</div>' +
'</div>' +
'</div>';
});
});
$.each(data.OrderDto, function (key, value) {
if (value.IsSAPMigrationflag === true) {
refundhtmlstr = '<div class="notify-reason"><span class="note"><B>Notification : </B> Geçmiş siparişleriniz yükleniyor. Lütfen kısa bir süre sonra tekrar kontrol ediniz. Teşekkürler. </span></div>';
}
});
}
$('#orders').html(htmlStr);
$("#notification").html(refundhtmlstr);
ApplySlide();
},
error: function () {
console.log("System Failure");
}
});
}
}
Web.config
Include UI origin and set Allow Credentials to true
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://burada.com" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
Three main kinds of browser-based storage:
session storage
local storage
cookie storage
Secure cookies - are used by encrypted websites to offer protection from any possible threats from a hacker.
access cookie - document.cookie. This means that this cookie is exposed and can be exploited through cross-site scripting. The saved cookie values can be seen through the browser console.
As a precaution, you should always try to make your cookies inaccessible on the client-side using JavaScript.
HTTPonly - ensures that a cookie is not accessible using the JavaScript code. This is the most crucial form of protection against cross-scripting attacks.
A secure attribute - ensures that the browser will reject cookies unless the connection happens over HTTPS.
sameSite attribute improves cookie security and avoids privacy leaks.
sameSite=Lax - It is set to Lax (sameSite = Lax) meaning a cookie is only set when the domain in the URL of the browser matches the domain of the cookie, thus eliminating third party’s domains. This will restrict cross-site sharing even between different domains that the same publisher owns. we need to include SameSite=None to avoid the new default of Lax:
Note: There is a draft spec that requires that the Secure attribute be set to true when the SameSite attribute has been set to 'none'. Some web browsers or other clients may be adopting this specification.
Using includes as { withCredentials: true } must include all the cookies with the request from the front end.
const data = { email: 'youremailaddress#gmail.com' , password: '1234' };
const response = await axios.post('www.yourapi.com/login', data , { withCredentials: true });
Cookie should only be accepted over a secure HTTPS connection. In order to get this to work, we must move the web application to HTTPS.
In express.js
res.cookie('token', token, {
maxAge: 1000 * 60 * 60 * 24, // would expire after (for 15 minutes 1000 * 60 * 15 ) 15 minutes
httpOnly: true, // The cookie only accessible by the web server
sameSite: 'none',
secure: true, // Marks the cookie to be used with HTTPS only.
});
Reference 1, Reference 2
Read Cookie in Web Api
var cookie = actionContext.Request.Headers.GetCookies("newhbsslv1");
Logger.Log("Cookie " + cookie, LoggerLevel.Info);
Logger.Log("Cookie count " + cookie.Count, LoggerLevel.Info);
if (cookie != null && cookie.Count > 0)
{
Logger.Log("Befor For " , LoggerLevel.Info);
foreach (var perCookie in cookie[0].Cookies)
{
Logger.Log("perCookie " + perCookie, LoggerLevel.Info);
if (perCookie.Name == "newhbsslv1")
{
strToken = perCookie.Value;
}
}
}

HTTP Caching - Asset not serving from browser cache after setting Cache-Control Header

Initial Request
Second Request
I am using a node module(express-cache-ctrl) to enable caching on a a proxy .
app.use(cache.public(3600));
My static assets have a Cache-control header on them with max-age . I am unable to figure out why they reload on a refresh and not served from browser-cache .
Edit : `
var onProxyRes = function(proxyRes, req, res) {
if ( proxyRes.headers["content-type"] == "text/css" ||
proxyRes.headers["content-type"] == "application/javascript") {
proxyRes.headers["Cache-Control"] = "public, max-age=86400";
}
//add something here to modify proxy response
};`
Tried manually adding caching header on proxy response also doesn't cache assets
Found this in a Chrome forum , while running a https server if you have any kind of SSL error then in that case browser prevents caching over HTTPS
https://bugs.chromium.org/p/chromium/issues/detail?id=110649. Works for me now

How can I build a private web widget (JS) that only trial or paid subscribers can use it?

I'm building a web widget that must be private (only trial/paid subscribers can use it).
Yeah, I know there's no secure way to accomplish 100% of security using a client side solution (JS). However, my intention is just to make it as difficult as possible.
So, here's the thing:
The user must register and provide his site's domain during registration. After that, he will get a 7 day trial and can configure his widget on my control panel.
After configuration he will be able to copy and paste the JS snippet that will load the widget's content later on his site. Ex:
<script>
(function(){
jQuery(document).ready(function($) {
var token = 'f04e42bae1b330bdc35351f6f709f66b';
var data = {'product_id': 123};
$.ajax({
url: 'https://myserver.com/widget.php',
type: 'POST',
data: JSON.stringify(data),
contentType: "application/json",
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', token);
}
}).done(function(data) {
console.log(data);
})
});
})();
</script>
PS: the production version of this snippet would be obsfucated.
Now I need to be able to control on my backend who is trying to load my widget's content. Currently, I'm doing the following:
Search for a user who has a token equal to the provided token and has an active subscription (trial or paid);
If user is found, set header "Allow-Control-Access-Origin" and proceed with the widget logic;
If no user is found, no header is set so browser will not load the content due to the "Same Origin Policy".
Ex:
<?php
$token = $_SERVER['HTTP_AUTHORIZATION'];
$productId = $_POST['product_id'];
$user = getUserByToken($token);
if($user){
header("Access-Control-Allow-Origin: //" . $user->domain);
$w = new Widget($user);
$items = $w->getItems($productId);
...
}
?>
Here is what Chrome responds when no "Access-Control-Allow-Origin" header is set (in case the token is not valid or is indeed valid but your origin domain does not match the one that is expected):
XMLHttpRequest cannot load http://myserver.com/widget.php. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8001' is therefore not allowed access.
I understand that even if a user tries to use my widget on his site without paying for it using someone else's snippet/token, the "Same Origin Policy" will prevent him from doing so (browser will block it as above) because the domains will not match, right?
Is this method somewhat secure? Or there is a better and more secure way to accomplish this requirement? Any suggestions for the overall solution?
Thanks!

js php, ajax remembers previously loaded content

I have the weird issue, I have been looking for the solution for a while with no result. I'm developing a website, decided to load every subpage(content) dynamically via AJAX(also .js and .css files for each subpage). Now, when I'm working on it and change scripts/css for some file and refresh the page, it doesn't load them. It's like AJAX remembers the previous version, because when I turn it all of and come back after few hours it changes (!). Any ideas for this one? I want to avoid remembering anything by site memory(or anything) so I could work on this normally. I don't use jquery, I use pure js and my own function for ajax connection, maybe I should add there something? Here it is:
function sendQuery( data )
{
var http = new XMLHttpRequest();
var url = data["url"];
var params = "";
var query = data["params"];
for(var key in query)
params+=key+"="+query[key]+"&";
params=params.substring(0,params.length-1);
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.send(params);
http.onreadystatechange = function()
{
if(http.readyState == 4 && http.status == 200)
{
data["result"](http.responseText);
}
}
}
Not sure entirely what you mean, but this sounds like a caching issue, why not append the current time or a similar random string to the request as a separate parameter? This level of uniqueness should prevent the request response from being cached by the browser.
e.g. '?nocache='+new Date().getTime()
You may also want to prevent the server side response from caching the content returned by the call by setting the appropriate headers (e.g.):
response.setHeader( "Pragma", "no-cache" );
response.setHeader( "Cache-Control", "no-cache" );
response.setDateHeader( "Expires", 0 );
It seems highly related with your caching policy.
If you're hosting site with apache,
Check .htaccess in your root directory you might see something like this:
# Set up 2 Hour caching on commonly updated files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresDefault A7200
Header append Cache-Control "proxy-revalidate"
</FilesMatch>
The setting above set expire time to 7200 seconds = 2 hours.
To disable cache under development:
# Force no caching for dynamic files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresActive Off
Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
Then it should works properly.
Another way is to change this line:
var url = data["url"];
To:
var url = data["url"]+"&ts="+(new Date().valueOf());
To avoid the cache. Note: it's just pseudo code. "?" Should be handled if there hasn't one.
Hope it helps :)

Categories

Resources