Browse Source

further address #853

pull/2/head
gorhill 7 years ago
parent
commit
e278a7d4e3
No known key found for this signature in database GPG Key ID: 25E1490B761470C2
  1. 174
      src/js/cookies.js

174
src/js/cookies.js

@ -41,10 +41,10 @@
var µm = µMatrix; var µm = µMatrix;
var recordPageCookiesQueue = {};
var removePageCookiesQueue = {};
var removeCookieQueue = {};
var cookieDict = {};
var recordPageCookiesQueue = new Map();
var removePageCookiesQueue = new Map();
var removeCookieQueue = new Set();
var cookieDict = new Map();
var cookieEntryJunkyard = []; var cookieEntryJunkyard = [];
var processRemoveQueuePeriod = 2 * 60 * 1000; var processRemoveQueuePeriod = 2 * 60 * 1000;
var processCleanPeriod = 10 * 60 * 1000; var processCleanPeriod = 10 * 60 * 1000;
@ -54,10 +54,11 @@ var processPageRemoveQueueTimer = null;
/******************************************************************************/ /******************************************************************************/
var CookieEntry = function(cookie) { var CookieEntry = function(cookie) {
this.set(cookie);
this.usedOn = new Set();
this.init(cookie);
}; };
CookieEntry.prototype.set = function(cookie) {
CookieEntry.prototype.init = function(cookie) {
this.secure = cookie.secure; this.secure = cookie.secure;
this.session = cookie.session; this.session = cookie.session;
this.anySubdomain = cookie.domain.charAt(0) === '.'; this.anySubdomain = cookie.domain.charAt(0) === '.';
@ -67,36 +68,37 @@ CookieEntry.prototype.set = function(cookie) {
this.name = cookie.name; this.name = cookie.name;
this.value = cookie.value; this.value = cookie.value;
this.tstamp = Date.now(); this.tstamp = Date.now();
this.usedOn = {};
this.usedOn.clear();
return this; return this;
}; };
// Release anything which may consume too much memory // Release anything which may consume too much memory
CookieEntry.prototype.unset = function() {
CookieEntry.prototype.dispose = function() {
this.hostname = ''; this.hostname = '';
this.domain = ''; this.domain = '';
this.path = ''; this.path = '';
this.name = ''; this.name = '';
this.value = ''; this.value = '';
this.usedOn = {};
this.usedOn.clear();
return this; return this;
}; };
/******************************************************************************/ /******************************************************************************/
var addCookieToDict = function(cookie) { var addCookieToDict = function(cookie) {
var cookieKey = cookieKeyFromCookie(cookie);
if ( cookieDict.hasOwnProperty(cookieKey) === false ) {
var cookieEntry = cookieEntryJunkyard.pop();
var cookieKey = cookieKeyFromCookie(cookie),
cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) {
cookieEntry = cookieEntryJunkyard.pop();
if ( cookieEntry ) { if ( cookieEntry ) {
cookieEntry.set(cookie);
cookieEntry.init(cookie);
} else { } else {
cookieEntry = new CookieEntry(cookie); cookieEntry = new CookieEntry(cookie);
} }
cookieDict[cookieKey] = cookieEntry;
cookieDict.set(cookieKey, cookieEntry);
} }
return cookieDict[cookieKey];
return cookieEntry;
}; };
/******************************************************************************/ /******************************************************************************/
@ -111,13 +113,11 @@ var addCookiesToDict = function(cookies) {
/******************************************************************************/ /******************************************************************************/
var removeCookieFromDict = function(cookieKey) { var removeCookieFromDict = function(cookieKey) {
if ( cookieDict.hasOwnProperty(cookieKey) === false ) {
return false;
}
var cookieEntry = cookieDict[cookieKey];
delete cookieDict[cookieKey];
var cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) { return false; }
cookieDict.delete(cookieKey);
if ( cookieEntryJunkyard.length < 25 ) { if ( cookieEntryJunkyard.length < 25 ) {
cookieEntryJunkyard.push(cookieEntry.unset());
cookieEntryJunkyard.push(cookieEntry.dispose());
} }
return true; return true;
}; };
@ -159,12 +159,6 @@ var cookieKeyFromCookieURL = function(url, type, name) {
/******************************************************************************/ /******************************************************************************/
var cookieEntryFromCookie = function(cookie) {
return cookieDict[cookieKeyFromCookie(cookie)];
};
/******************************************************************************/
var cookieURLFromCookieEntry = function(entry) { var cookieURLFromCookieEntry = function(entry) {
if ( !entry ) { if ( !entry ) {
return ''; return '';
@ -175,10 +169,8 @@ var cookieURLFromCookieEntry = function(entry) {
/******************************************************************************/ /******************************************************************************/
var cookieMatchDomains = function(cookieKey, allHostnamesString) { var cookieMatchDomains = function(cookieKey, allHostnamesString) {
var cookieEntry = cookieDict[cookieKey];
if ( !cookieEntry ) {
return false;
}
var cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) { return false; }
if ( allHostnamesString.indexOf(' ' + cookieEntry.hostname + ' ') < 0 ) { if ( allHostnamesString.indexOf(' ' + cookieEntry.hostname + ' ') < 0 ) {
if ( !cookieEntry.anySubdomain ) { if ( !cookieEntry.anySubdomain ) {
return false; return false;
@ -202,7 +194,7 @@ var recordPageCookiesAsync = function(pageStats) {
if ( !pageStats ) { if ( !pageStats ) {
return; return;
} }
recordPageCookiesQueue[pageStats.pageUrl] = pageStats;
recordPageCookiesQueue.set(pageStats.pageUrl, pageStats);
if ( processPageRecordQueueTimer === null ) { if ( processPageRecordQueueTimer === null ) {
processPageRecordQueueTimer = vAPI.setTimeout(processPageRecordQueue, 1000); processPageRecordQueueTimer = vAPI.setTimeout(processPageRecordQueue, 1000);
} }
@ -220,11 +212,9 @@ var cookieLogEntryBuilder = [
]; ];
var recordPageCookie = function(pageStore, cookieKey) { var recordPageCookie = function(pageStore, cookieKey) {
if ( vAPI.isBehindTheSceneTabId(pageStore.tabId) ) {
return;
}
if ( vAPI.isBehindTheSceneTabId(pageStore.tabId) ) { return; }
var cookieEntry = cookieDict[cookieKey];
var cookieEntry = cookieDict.get(cookieKey);
var pageHostname = pageStore.pageHostname; var pageHostname = pageStore.pageHostname;
var block = µm.mustBlock(pageHostname, cookieEntry.hostname, 'cookie'); var block = µm.mustBlock(pageHostname, cookieEntry.hostname, 'cookie');
@ -240,7 +230,7 @@ var recordPageCookie = function(pageStore, cookieKey) {
pageStore.recordRequest('cookie', cookieURL, block); pageStore.recordRequest('cookie', cookieURL, block);
µm.logger.writeOne(pageStore.tabId, 'net', pageHostname, cookieURL, 'cookie', block); µm.logger.writeOne(pageStore.tabId, 'net', pageHostname, cookieURL, 'cookie', block);
cookieEntry.usedOn[pageHostname] = true;
cookieEntry.usedOn.add(pageHostname);
// rhill 2013-11-21: // rhill 2013-11-21:
// https://github.com/gorhill/httpswitchboard/issues/65 // https://github.com/gorhill/httpswitchboard/issues/65
@ -267,7 +257,7 @@ var removePageCookiesAsync = function(pageStats) {
if ( !pageStats ) { if ( !pageStats ) {
return; return;
} }
removePageCookiesQueue[pageStats.pageUrl] = pageStats;
removePageCookiesQueue.set(pageStats.pageUrl, pageStats);
if ( processPageRemoveQueueTimer === null ) { if ( processPageRemoveQueueTimer === null ) {
processPageRemoveQueueTimer = vAPI.setTimeout(processPageRemoveQueue, 15 * 1000); processPageRemoveQueueTimer = vAPI.setTimeout(processPageRemoveQueue, 15 * 1000);
} }
@ -278,7 +268,7 @@ var removePageCookiesAsync = function(pageStats) {
// Candidate for removal // Candidate for removal
var removeCookieAsync = function(cookieKey) { var removeCookieAsync = function(cookieKey) {
removeCookieQueue[cookieKey] = true;
removeCookieQueue.add(cookieKey);
}; };
/******************************************************************************/ /******************************************************************************/
@ -318,13 +308,10 @@ var i18nCookieDeleteFailure = vAPI.i18n('loggerEntryDeleteCookieError');
var processPageRecordQueue = function() { var processPageRecordQueue = function() {
processPageRecordQueueTimer = null; processPageRecordQueueTimer = null;
for ( var pageURL in recordPageCookiesQueue ) {
if ( !recordPageCookiesQueue.hasOwnProperty(pageURL) ) {
continue;
}
findAndRecordPageCookies(recordPageCookiesQueue[pageURL]);
delete recordPageCookiesQueue[pageURL];
for ( var pageStore of recordPageCookiesQueue.values() ) {
findAndRecordPageCookies(pageStore);
} }
recordPageCookiesQueue.clear();
}; };
/******************************************************************************/ /******************************************************************************/
@ -332,13 +319,10 @@ var processPageRecordQueue = function() {
var processPageRemoveQueue = function() { var processPageRemoveQueue = function() {
processPageRemoveQueueTimer = null; processPageRemoveQueueTimer = null;
for ( var pageURL in removePageCookiesQueue ) {
if ( !removePageCookiesQueue.hasOwnProperty(pageURL) ) {
continue;
}
findAndRemovePageCookies(removePageCookiesQueue[pageURL]);
delete removePageCookiesQueue[pageURL];
for ( var pageStore of removePageCookiesQueue.values() ) {
findAndRemovePageCookies(pageStore);
} }
removePageCookiesQueue.clear();
}; };
/******************************************************************************/ /******************************************************************************/
@ -359,19 +343,12 @@ var processRemoveQueue = function() {
var srcHostnames; var srcHostnames;
var cookieEntry; var cookieEntry;
for ( var cookieKey in removeCookieQueue ) {
if ( removeCookieQueue.hasOwnProperty(cookieKey) === false ) {
continue;
}
delete removeCookieQueue[cookieKey];
for ( var cookieKey of removeCookieQueue ) {
// rhill 2014-05-12: Apparently this can happen. I have to // rhill 2014-05-12: Apparently this can happen. I have to
// investigate how (A session cookie has same name as a // investigate how (A session cookie has same name as a
// persistent cookie?) // persistent cookie?)
cookieEntry = cookieDict[cookieKey];
if ( !cookieEntry ) {
continue;
}
cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) { continue; }
// Delete obsolete session cookies: enabled. // Delete obsolete session cookies: enabled.
if ( tstampObsolete !== 0 && cookieEntry.session ) { if ( tstampObsolete !== 0 && cookieEntry.session ) {
@ -399,6 +376,8 @@ var processRemoveQueue = function() {
} }
} }
removeCookieQueue.clear();
vAPI.setTimeout(processRemoveQueue, processRemoveQueuePeriod); vAPI.setTimeout(processRemoveQueue, processRemoveQueuePeriod);
}; };
@ -407,16 +386,29 @@ var processRemoveQueue = function() {
// Once in a while, we go ahead and clean everything that might have been // Once in a while, we go ahead and clean everything that might have been
// left behind. // left behind.
// Remove only some of the cookies which are candidate for removal: who knows,
// maybe a user has 1000s of cookies sitting in his browser...
var processClean = function() { var processClean = function() {
// Remove only some of the cookies which are candidate for removal:
// who knows, maybe a user has 1000s of cookies sitting in his
// browser...
var cookieKeys = Object.keys(cookieDict);
if ( cookieKeys.length > 25 ) {
cookieKeys = cookieKeys.sort(function(){return Math.random() < 0.5;}).splice(0, 50);
var us = µm.userSettings;
if ( us.deleteCookies || us.deleteUnusedSessionCookies ) {
var cookieKeys = Array.from(cookieDict.keys()),
len = cookieKeys.length,
step, offset, n;
if ( len > 25 ) {
step = len / 25;
offset = Math.floor(Math.random() * len);
n = 25;
} else {
step = 1;
offset = 0;
n = len;
}
var i = offset;
while ( n-- ) {
removeCookieAsync(cookieKeys[Math.floor(i % len)]);
i += step;
} }
while ( cookieKeys.length ) {
removeCookieAsync(cookieKeys.pop());
} }
vAPI.setTimeout(processClean, processCleanPeriod); vAPI.setTimeout(processClean, processCleanPeriod);
@ -425,45 +417,33 @@ var processClean = function() {
/******************************************************************************/ /******************************************************************************/
var findAndRecordPageCookies = function(pageStore) { var findAndRecordPageCookies = function(pageStore) {
for ( var cookieKey in cookieDict ) {
if ( !cookieDict.hasOwnProperty(cookieKey) ) {
continue;
}
if ( cookieMatchDomains(cookieKey, pageStore.allHostnamesString) === false ) {
continue;
}
for ( var cookieKey of cookieDict.keys() ) {
if ( cookieMatchDomains(cookieKey, pageStore.allHostnamesString) ) {
recordPageCookie(pageStore, cookieKey); recordPageCookie(pageStore, cookieKey);
} }
}
}; };
/******************************************************************************/ /******************************************************************************/
var findAndRemovePageCookies = function(pageStore) { var findAndRemovePageCookies = function(pageStore) {
for ( var cookieKey in cookieDict ) {
if ( !cookieDict.hasOwnProperty(cookieKey) ) {
continue;
}
if ( !cookieMatchDomains(cookieKey, pageStore.allHostnamesString) ) {
continue;
}
for ( var cookieKey of cookieDict.keys() ) {
if ( cookieMatchDomains(cookieKey, pageStore.allHostnamesString) ) {
removeCookieAsync(cookieKey); removeCookieAsync(cookieKey);
} }
}
}; };
/******************************************************************************/ /******************************************************************************/
var canRemoveCookie = function(cookieKey, srcHostnames) { var canRemoveCookie = function(cookieKey, srcHostnames) {
var cookieEntry = cookieDict[cookieKey];
if ( !cookieEntry ) {
return false;
}
var cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) { return false; }
var cookieHostname = cookieEntry.hostname; var cookieHostname = cookieEntry.hostname;
var srcHostname; var srcHostname;
for ( srcHostname in cookieEntry.usedOn ) {
if ( cookieEntry.usedOn.hasOwnProperty(srcHostname) === false ) {
continue;
}
for ( srcHostname of cookieEntry.usedOn ) {
if ( µm.mustAllow(srcHostname, cookieHostname, 'cookie') ) { if ( µm.mustAllow(srcHostname, cookieHostname, 'cookie') ) {
return false; return false;
} }
@ -500,14 +480,12 @@ vAPI.cookies.onChanged = function(cookie) {
// rhill 2013-12-11: If cookie value didn't change, no need to record. // rhill 2013-12-11: If cookie value didn't change, no need to record.
// https://github.com/gorhill/httpswitchboard/issues/79 // https://github.com/gorhill/httpswitchboard/issues/79
var cookieKey = cookieKeyFromCookie(cookie); var cookieKey = cookieKeyFromCookie(cookie);
var cookieEntry = cookieDict[cookieKey];
if ( !cookieEntry ) {
var cookieEntry = cookieDict.get(cookieKey);
if ( cookieEntry === undefined ) {
cookieEntry = addCookieToDict(cookie); cookieEntry = addCookieToDict(cookie);
} else { } else {
cookieEntry.tstamp = Date.now(); cookieEntry.tstamp = Date.now();
if ( cookie.value === cookieEntry.value ) {
return;
}
if ( cookie.value === cookieEntry.value ) { return; }
cookieEntry.value = cookie.value; cookieEntry.value = cookie.value;
} }
@ -543,8 +521,8 @@ vAPI.cookies.onRemoved = function(cookie) {
// Listen to any change in cookieland, we will update page stats accordingly. // Listen to any change in cookieland, we will update page stats accordingly.
vAPI.cookies.onAllRemoved = function() { vAPI.cookies.onAllRemoved = function() {
for ( var cookieKey in cookieDict ) {
if ( cookieDict.hasOwnProperty(cookieKey) && removeCookieFromDict(cookieKey) ) {
for ( var cookieKey of cookieDict.keys() ) {
if ( removeCookieFromDict(cookieKey) ) {
µm.logger.writeOne('', 'info', 'cookie', i18nCookieDeleteSuccess.replace('{{value}}', cookieKey)); µm.logger.writeOne('', 'info', 'cookie', i18nCookieDeleteSuccess.replace('{{value}}', cookieKey));
} }
} }

Loading…
Cancel
Save