Browse Source

various fixes

pull/2/head
gorhill 10 years ago
parent
commit
4ad7c65362
  1. 2
      platform/firefox/vapi-background.js
  2. 49
      src/css/logger-ui.css
  3. 2
      src/css/popup.css
  4. 30
      src/js/cookies.js
  5. 70
      src/js/logger-ui.js
  6. 39
      src/js/logger.js
  7. 1
      src/js/messaging.js
  8. 14
      src/js/tab.js
  9. 109
      src/js/traffic.js
  10. 8
      src/js/uritools.js

2
platform/firefox/vapi-background.js

@ -1971,7 +1971,7 @@ vAPI.cookies.getAll = function(callback) {
vAPI.cookies.remove = function(details, callback) {
// TODO
if ( typeof callback === 'function' ) {
callback();
callback(null);
}
};
/******************************************************************************/

49
src/css/logger-ui.css

@ -1,6 +1,8 @@
body {
background-color: white;
border: 0;
box-sizing: border-box;
color: black;
-moz-box-sizing: border-box;
margin: 0;
overflow-x: hidden;
@ -57,67 +59,62 @@ input:focus {
}
#content table tr {
background-color: #fafafa;
color: #444;
}
#content table tr.cat_info {
color: #00a;
color: #00f;
}
#content table tr.blocked {
color: #c00;
color: #f00;
}
#content table tr:nth-of-type(2n+1) {
background-color: #eee;
}
#content table tr > td[colspan="3"]:nth-of-type(2) {
white-space: normal;
word-break: break-all;
word-wrap: break-word;
}
#content table tr.doc {
background-color: #666;
color: white;
text-align: center;
}
#content table tr.doc > td {
border: 0;
}
#content table tr.doc > td:nth-of-type(2) {
padding: 0.6em 0;
}
/*
#content table tr.allowed {
background-color: rgba(0, 160, 0, 0.1);
}
#content table tr.allowed:nth-of-type(2n+1) {
background-color: rgba(0, 160, 0, 0.2);
}
body.colorBlind #content table tr.allowed {
background-color: rgba(255, 194, 57, 0.1)
}
*/
body:not(.filterOff) #content table tr.hidden {
display: none;
}
#content table tr td {
border: 1px solid #ccc;
min-width: 0.5em;
padding: 3px;
vertical-align: top;
}
#content table tr.doc > td {
border: 0;
}
#content table tr td:nth-of-type(1) {
text-align: center;
white-space: pre;
width: 8em;
}
#content table tr td:nth-of-type(2) {
width: 1em;
}
#content table tr td:nth-of-type(3) {
white-space: pre;
width: 2em;
}
#content table tr td:nth-of-type(3) {
#content table tr td:nth-of-type(4) {
white-space: pre;
width: 8em;
}
#content table tr td:nth-of-type(4) {
#content table tr td:nth-of-type(5) {
border-right: none;
white-space: normal;
word-break: break-all;
word-wrap: break-word;
}
#content table tr.tab_bts > td:nth-of-type(2):before {
content: '\f070';
font: 1em FontAwesome;
}
#content table tr > td[colspan="3"]:nth-of-type(3) {
white-space: normal;
word-break: break-all;
word-wrap: break-word;
}

2
src/css/popup.css

@ -69,7 +69,7 @@ body .toolbar button.disabled {
color: #ccc;
}
body .toolbar button.fa {
font: 1.75em 'FontAwesome';
font: 1.75em FontAwesome;
min-width: 1.1em;
}
body.tScopeGlobal .scopeRel:not(.disabled) {

30
src/js/cookies.js

@ -287,20 +287,28 @@ var removeCookieAsync = function(cookieKey) {
/******************************************************************************/
// TODO: i18n
var chromeCookieRemove = function(url, name) {
var sessionCookieKey = cookieKeyFromCookieURL(url, 'session', name);
var persistCookieKey = cookieKeyFromCookieURL(url, 'persistent', name);
var callback = function(details) {
if ( !details ) {
return;
}
var cookieKey = cookieKeyFromCookieURL(details.url, 'session', details.name);
if ( removeCookieFromDict(cookieKey) ) {
µm.logger.writeOne('', 'info', 'cookie deleted: ' + cookieKey);
µm.cookieRemovedCounter += 1;
var success = !!details;
if ( cookieDict.hasOwnProperty(sessionCookieKey) ) {
if ( success ) {
µm.logger.writeOne('', 'info', 'cookie deleted: ' + sessionCookieKey);
µm.cookieRemovedCounter += 1;
} else {
µm.logger.writeOne('', 'error', 'failed to delete cookie: ' + sessionCookieKey);
}
}
cookieKey = cookieKeyFromCookieURL(details.url, 'persistent', details.name);
if ( removeCookieFromDict(cookieKey) ) {
µm.logger.writeOne('', 'info', 'cookie deleted: ' + cookieKey);
µm.cookieRemovedCounter += 1;
if ( cookieDict.hasOwnProperty(persistCookieKey) ) {
if ( success ) {
µm.logger.writeOne('', 'info', 'cookie deleted: ' + persistCookieKey);
µm.cookieRemovedCounter += 1;
} else {
µm.logger.writeOne('', 'error', 'failed to delete cookie: ' + persistCookieKey);
}
}
};

70
src/js/logger-ui.js

@ -41,8 +41,9 @@ var body = doc.body;
var tbody = doc.querySelector('#content tbody');
var trJunkyard = [];
var tdJunkyard = [];
var firstVarDataCol = 1;
var lastVarDataCol = 3;
var firstVarDataCol = 2; // currently, column 2 (0-based index)
var lastVarDataIndex = 3; // currently, d0-d3
var noTabId = '';
var prettyRequestTypes = {
'main_frame': 'doc',
@ -61,12 +62,22 @@ var timeOptions = {
/******************************************************************************/
var createCell = function() {
var td = tdJunkyard.pop();
var createCellAt = function(tr, index) {
var td = tr.cells[index];
var mustAppend = !td;
if ( mustAppend ) {
td = tdJunkyard.pop();
}
if ( td ) {
return td;
td.removeAttribute('colspan');
td.textContent = '';
} else {
td = doc.createElement('td');
}
return doc.createElement('td');
if ( mustAppend ) {
tr.appendChild(td);
}
return td;
};
/******************************************************************************/
@ -78,23 +89,13 @@ var createRow = function(entry) {
} else {
tr = doc.createElement('tr');
}
var td;
for ( var index = 0; index < firstVarDataCol; index++ ) {
td = tr.cells[index];
if ( td === undefined ) {
td = createCell();
tr.appendChild(td);
}
td.removeAttribute('colspan');
createCellAt(tr, index);
}
var i = 1, span = 1;
var i = 1, span = 1, td;
for (;;) {
td = tr.cells[index];
if ( td === undefined ) {
td = createCell();
tr.appendChild(td);
}
if ( i === lastVarDataCol ) {
td = createCellAt(tr, index);
if ( i === lastVarDataIndex ) {
break;
}
if ( entry['d' + i] === undefined ) {
@ -102,8 +103,6 @@ var createRow = function(entry) {
} else {
if ( span !== 1 ) {
td.setAttribute('colspan', span);
} else {
td.removeAttribute('colspan');
}
index += 1;
span = 1;
@ -112,8 +111,6 @@ var createRow = function(entry) {
}
if ( span !== 1 ) {
td.setAttribute('colspan', span);
} else {
td.removeAttribute('colspan');
}
index += 1;
while ( td = tr.cells[index] ) {
@ -134,17 +131,25 @@ var createGap = function(url) {
/******************************************************************************/
var renderLogEntry = function(entry) {
var fvdc = firstVarDataCol;
var tr = createRow(entry);
tr.classList.add('tab_' + entry.tab);
tr.classList.add('cat_' + entry.cat);
if ( entry.tab === noTabId ) {
tr.classList.add('tab_bts');
} else if ( entry.tab !== '' ) {
tr.classList.add('tab_' + entry.tab);
}
if ( entry.cat !== '' ) {
tr.classList.add('cat_' + entry.cat);
}
var time = new Date(entry.tstamp);
tr.cells[0].textContent = time.toLocaleString('fullwide', timeOptions);
switch ( entry.cat ) {
case 'error':
case 'info':
tr.cells[firstVarDataCol].textContent = entry.d0;
tr.cells[fvdc].textContent = entry.d0;
break;
case 'net':
@ -155,15 +160,16 @@ var renderLogEntry = function(entry) {
}
if ( entry.d0 ) {
tr.classList.add('blocked');
tr.cells[1].textContent = '---';
tr.cells[fvdc].textContent = '---';
} else {
tr.cells[1].textContent = '';
tr.cells[fvdc].textContent = '';
}
tr.cells[2].textContent = (prettyRequestTypes[entry.d1] || entry.d1) + '\t';
tr.cells[3].textContent = entry.d2 + '\t';
tr.cells[fvdc+1].textContent = (prettyRequestTypes[entry.d1] || entry.d1) + '\t';
tr.cells[fvdc+2].textContent = entry.d2 + '\t';
break;
default:
tr.cells[fvdc].textContent = entry.d0;
break;
}
@ -178,6 +184,8 @@ var renderLogBuffer = function(response) {
return;
}
noTabId = response.noTabId;
// Preserve scroll position
var height = tbody.offsetHeight;

39
src/js/logger.js

@ -64,7 +64,9 @@ LogEntry.prototype.init = function(args) {
/******************************************************************************/
LogEntry.prototype.dispose = function() {
this.url = this.hostname = this.type = this.result = '';
this.tstamp = 0;
this.tab = this.cat = '';
this.d0 = this.d1 = this.d2 = this.d3 = undefined;
if ( logEntryJunkyard.length < logEntryJunkyardMax ) {
logEntryJunkyard.push(this);
}
@ -152,16 +154,26 @@ var logBuffer = null;
// thus removed from memory.
var logBufferObsoleteAfter = 60 * 1000;
// The janitor will look for stale log buffer every 2 minutes.
var loggerJanitorPeriod = 2 * 60 * 1000;
/******************************************************************************/
var janitor = function() {
if (
logBuffer !== null &&
logBuffer.lastReadTime < (Date.now() - logBufferObsoleteAfter)
) {
logBuffer = logBuffer.dispose();
}
if ( logBuffer !== null ) {
setTimeout(janitor, logBufferObsoleteAfter);
}
};
/******************************************************************************/
var writeOne = function() {
if ( logBuffer === null ) {
return;
if ( logBuffer !== null ) {
logBuffer.writeOne(arguments);
}
logBuffer.writeOne(arguments);
};
/******************************************************************************/
@ -169,26 +181,13 @@ var writeOne = function() {
var readAll = function(tabId) {
if ( logBuffer === null ) {
logBuffer = new LogBuffer();
setTimeout(janitor, logBufferObsoleteAfter);
}
return logBuffer.readAll();
};
/******************************************************************************/
var loggerJanitor = function() {
if (
logBuffer !== null &&
logBuffer.lastReadTime < (Date.now() - logBufferObsoleteAfter)
) {
logBuffer = logBuffer.dispose();
}
setTimeout(loggerJanitor, loggerJanitorPeriod);
};
setTimeout(loggerJanitor, loggerJanitorPeriod);
/******************************************************************************/
return {
writeOne: writeOne,
readAll: readAll

1
src/js/messaging.js

@ -974,6 +974,7 @@ var onMessage = function(request, sender, callback) {
case 'readMany':
response = {
colorBlind: false,
noTabId: vAPI.noTabId,
entries: µm.logger.readAll(request.tabId)
};
break;

14
src/js/tab.js

@ -157,8 +157,10 @@ housekeep itself.
this.stack = [];
this.rawURL =
this.normalURL =
this.scheme =
this.rootHostname =
this.rootDomain = '';
this.secure = false;
this.timer = null;
this.onTabCallback = null;
this.onTimerCallback = null;
@ -209,13 +211,19 @@ housekeep itself.
// root URL.
TabContext.prototype.update = function() {
if ( this.stack.length === 0 ) {
this.rawURL = this.normalURL = this.rootHostname = this.rootDomain = '';
this.rawURL =
this.normalURL =
this.scheme =
this.rootHostname =
this.rootDomain = '';
} else {
this.rawURL = this.stack[this.stack.length - 1];
this.normalURL = µm.normalizePageURL(this.tabId, this.rawURL);
this.scheme = µm.URI.schemeFromURI(this.rawURL);
this.rootHostname = µm.URI.hostnameFromURI(this.normalURL);
this.rootDomain = µm.URI.domainFromHostname(this.rootHostname) || this.rootHostname;
}
this.secure = µm.URI.isSecureScheme(this.scheme);
};
// Called whenever a candidate root URL is spotted for the tab.
@ -223,6 +231,10 @@ housekeep itself.
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
return;
}
var count = this.stack.length;
if ( count !== 0 && this.stack[count - 1] === url ) {
return;
}
this.stack.push(url);
this.update();
};

109
src/js/traffic.js

@ -73,11 +73,10 @@ var onBeforeRootFrameRequestHandler = function(details) {
var onBeforeRequestHandler = function(details) {
var µm = µMatrix;
var µmuri = µm.URI.set(details.url);
var requestScheme = µmuri.scheme;
// rhill 2014-02-17: Ignore 'filesystem:': this can happen when listening
// to 'chrome-extension://'.
var requestScheme = µm.URI.schemeFromURI(details.url);
if ( requestScheme === 'filesystem' ) {
return;
}
@ -96,7 +95,7 @@ var onBeforeRequestHandler = function(details) {
var requestURL = details.url;
// Ignore non-http schemes
if ( requestScheme.indexOf('http') !== 0 ) {
if ( requestScheme.lastIndexOf('http', 0) !== 0 ) {
return;
}
@ -115,10 +114,21 @@ var onBeforeRequestHandler = function(details) {
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
var tabContext = µm.tabContextManager.mustLookup(details.tabId);
var tabId = tabContext.tabId;
var requestHostname = µmuri.hostname;
// Enforce strict secure connection?
var block = false;
if (
tabContext.secure &&
µm.URI.isSecureScheme(requestScheme) === false &&
µm.tMatrix.evaluateSwitchZ('https-strict', tabContext.rootHostname)
) {
block = true;
}
// Disallow request as per temporary matrix?
var block = µm.mustBlock(tabContext.rootHostname, requestHostname, requestType);
if ( block === false ) {
block = µm.mustBlock(tabContext.rootHostname, details.hostname, requestType);
}
// Record request.
// https://github.com/gorhill/httpswitchboard/issues/342
@ -126,16 +136,16 @@ var onBeforeRequestHandler = function(details) {
// processing has already been performed, and that a synthetic URL has
// been constructed for logging purpose. Use this synthetic URL if
// it is available.
var pageStore = µm.mustPageStoreFromTabId(details.tabId);
var pageStore = µm.mustPageStoreFromTabId(tabContext.tabId);
pageStore.recordRequest(requestType, requestURL, block);
// whitelisted?
// Allowed?
if ( !block ) {
// console.debug('onBeforeRequestHandler()> ALLOW "%s": %o', details.url, details);
return;
}
// blacklisted
// Blocked
// console.debug('onBeforeRequestHandler()> BLOCK "%s": %o', details.url, details);
return { 'cancel': true };
@ -198,16 +208,14 @@ var onBeforeSendHeadersHandler = function(details) {
// If we reach this point, request is not blocked, so what is left to do
// is to sanitize headers.
var reqHostname = µm.hostnameFromURL(requestURL);
if ( µm.mustBlock(pageStore.pageHostname, reqHostname, 'cookie') ) {
if ( µm.mustBlock(pageStore.pageHostname, details.hostname, 'cookie') ) {
if ( details.requestHeaders.setHeader('cookie', '') ) {
µm.cookieHeaderFoiledCounter++;
}
}
if ( µm.tMatrix.evaluateSwitchZ('referrer-spoof', pageStore.pageHostname) ) {
foilRefererHeaders(µm, reqHostname, details);
foilRefererHeaders(µm, details.hostname, details);
}
if ( µm.tMatrix.evaluateSwitchZ('ua-spoof', pageStore.pageHostname) ) {
@ -267,83 +275,63 @@ var onHeadersReceived = function(details) {
var onMainDocHeadersReceived = function(details) {
var µm = µMatrix;
var tabId = details.tabId;
var requestURL = details.url;
// https://github.com/gorhill/uMatrix/issues/145
// Check if the main_frame is a download
if ( headerValue(details.responseHeaders, 'content-disposition').lastIndexOf('attachment', 0) === 0 ) {
µm.tabContextManager.unpush(details.tabId, details.url);
if ( headerValue(details.responseHeaders, 'content-type').lastIndexOf('application/x-', 0) === 0 ) {
µm.tabContextManager.unpush(tabId, requestURL);
} else {
µm.tabContextManager.push(tabId, requestURL);
}
var tabContext = µm.tabContextManager.lookup(details.tabId);
var tabContext = µm.tabContextManager.lookup(tabId);
if ( tabContext === null ) {
return;
}
// console.debug('onMainDocHeadersReceived()> "%s": %o', details.url, details);
// rhill 2013-12-07:
// Apparently in Opera, onBeforeRequest() is triggered while the
// URL is not yet bound to a tab (-1), which caused the code here
// to not be able to lookup the page store. So let the code here bind
// the page to a tab if not done yet.
// https://github.com/gorhill/httpswitchboard/issues/75
// TODO: check this works fine on Opera
// Re-classify orphan HTTP requests as behind-the-scene requests. There is
// not much else which can be done, because there are URLs
// which cannot be handled by HTTP Switchboard, i.e. `opera://startpage`,
// as this would lead to complications with no obvious solution, like how
// to scope on unknown scheme? Etc.
// https://github.com/gorhill/httpswitchboard/issues/191
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
var pageStore = µm.mustPageStoreFromTabId(details.tabId);
var headers = details.responseHeaders;
// Maybe modify inbound headers
var csp = '';
// console.debug('onMainDocHeadersReceived()> "%s": %o', requestURL, details);
// Enforce strict HTTPS?
var requestScheme = µm.URI.schemeFromURI(details.url);
if ( requestScheme === 'https' && µm.tMatrix.evaluateSwitchZ('https-strict', tabContext.rootHostname) ) {
csp += "default-src chrome-search: data: https: wss: 'unsafe-eval' 'unsafe-inline';";
}
var blockScript = µm.mustBlock(tabContext.rootHostname, tabContext.rootHostname, 'script');
// https://github.com/gorhill/httpswitchboard/issues/181
pageStore.pageScriptBlocked = µm.mustBlock(tabContext.rootHostname, tabContext.rootHostname, 'script');
if ( pageStore.pageScriptBlocked ) {
// If javascript not allowed, say so through a `Content-Security-Policy` directive.
// console.debug('onMainDocHeadersReceived()> PAGE CSP "%s": %o', details.url, details);
csp += " script-src 'none'";
var pageStore = µm.pageStoreFromTabId(tabId);
if ( pageStore ) {
pageStore.pageScriptBlocked = blockScript;
}
// https://github.com/gorhill/httpswitchboard/issues/181
if ( csp !== '' ) {
headers.push({
'name': 'Content-Security-Policy',
'value': csp.trim()
});
return { responseHeaders: headers };
if ( !blockScript ) {
return;
}
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', requestURL);
// If javascript not allowed, say so through a `Content-Security-Policy` directive.
details.responseHeaders.push({
'name': 'Content-Security-Policy',
'value': "script-src 'none'"
});
return { responseHeaders: details.responseHeaders };
};
/******************************************************************************/
var onSubDocHeadersReceived = function(details) {
var µm = µMatrix;
var tabId = details.tabId;
// console.debug('onSubDocHeadersReceived()> "%s": %o', details.url, details);
var µm = µMatrix;
// Do not ignore traffic outside tabs.
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
var tabId = details.tabId;
var tabContext = µm.tabContextManager.lookup(tabId);
if ( tabContext === null ) {
return;
}
// Evaluate
if ( µm.mustAllow(tabContext.rootHostname, µm.hostnameFromURL(details.url), 'script') ) {
if ( µm.mustAllow(tabContext.rootHostname, details.hostname, 'script') ) {
return;
}
@ -368,6 +356,9 @@ var onSubDocHeadersReceived = function(details) {
// console.debug('onSubDocHeadersReceived()> FRAME CSP "%s": %o, scope="%s"', details.url, details, pageURL);
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', details.url);
// If javascript not allowed, say so through a `Content-Security-Policy` directive.
details.responseHeaders.push({
'name': 'Content-Security-Policy',
'value': "script-src 'none'"

8
src/js/uritools.js

@ -236,6 +236,14 @@ URI.schemeFromURI = function(uri) {
/******************************************************************************/
URI.isSecureScheme = function(scheme) {
return scheme === 'https' ||
scheme === 'wss' ||
scheme === 'ftps';
};
/******************************************************************************/
URI.authorityFromURI = function(uri) {
var matches = reAuthorityFromURI.exec(uri);
if ( !matches ) {

Loading…
Cancel
Save