From 1597ce7fd91880b92f25b361167b3455d891a29a Mon Sep 17 00:00:00 2001 From: gorhill Date: Tue, 6 Jan 2015 08:01:15 -0500 Subject: [PATCH] lot of work related to dynamic filtering + new net requests logger --- platform/chromium/vapi-background.js | 9 + src/css/devtool-log.css | 68 +++++++ src/css/devtools.css | 49 +++++ src/css/popup.css | 105 ++++++---- src/css/stats.css | 86 -------- src/dashboard.html | 1 - src/devtool-log.html | 20 ++ src/devtools.html | 25 +++ src/js/background.js | 1 - src/js/cosmetic-filtering.js | 10 +- src/js/devtool-log.js | 178 ++++++++++++++++ src/js/devtools.js | 98 +++++++++ src/js/dynamic-net-filtering.js | 53 ++++- src/js/messaging.js | 125 +++++++----- src/js/pagestore.js | 294 ++++++++++++++++++++++----- src/js/popup.js | 161 ++++++++------- src/js/stats.js | 255 ----------------------- src/js/storage.js | 4 + src/js/tab.js | 7 +- src/js/traffic.js | 4 +- src/js/ublock.js | 71 +------ src/popup.html | 45 ++-- src/stats.html | 40 ---- 23 files changed, 991 insertions(+), 718 deletions(-) create mode 100644 src/css/devtool-log.css create mode 100644 src/css/devtools.css delete mode 100644 src/css/stats.css create mode 100644 src/devtool-log.html create mode 100644 src/devtools.html create mode 100644 src/js/devtool-log.js create mode 100644 src/js/devtools.js delete mode 100644 src/js/stats.js delete mode 100644 src/stats.html diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 6d4ff0217..76b25bf6c 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -208,6 +208,15 @@ vAPI.tabs.remove = function(tabId) { /******************************************************************************/ +vAPI.tabs.reload = function(tabId, flags) { + if ( typeof tabId === 'string' ) { + tabId = parseInt(tabId, 10); + } + chrome.tabs.reload(tabId); +}; + +/******************************************************************************/ + vAPI.tabs.injectScript = function(tabId, details, callback) { var onScriptExecuted = function() { // https://code.google.com/p/chromium/issues/detail?id=410868#c8 diff --git a/src/css/devtool-log.css b/src/css/devtool-log.css new file mode 100644 index 000000000..d4a21e0b9 --- /dev/null +++ b/src/css/devtool-log.css @@ -0,0 +1,68 @@ +body { + border: 0; + box-sizing: border-box; + font: 11px monospace; + margin: 0; + overflow-x: hidden; + padding: 0; + white-space: nowrap; + width: 100%; + } +#toolbar { + padding: 8px 0; + position: fixed; + text-align: center; + top: 0; + width: 4em; + } +#toolbar .button { + background-color: white; + border: none; + cursor: pointer; + display: block; + font-size: large; + margin: 0; + padding: 0.5em 0; + } +#toolbar .button:hover { + background-color: #eee; + } +#content { + margin-left: 4em; + width: calc(100% - 4em); + } +#content table { + border: 0; + border-collapse: collapse; + width: 100%; + } +#content table tr.blocked { + background-color: rgba(192, 0, 0, 0.1) + } +#content table tr.allowed { + background-color: rgba(0, 160, 0, 0.1) + } +#content table tr td { + border: 1px solid #ccc; + hyphens: none; + padding: 3px; + vertical-align: top; + white-space: normal; + word-break: break-all; + word-wrap: break-word; + } +#content table tr td:nth-of-type(1) { + width: 15%; + } +#content table tr td:nth-of-type(3) { + border-right: none; + width: 75%; + } +#content table tr.blocked td:nth-of-type(3) b { + background-color: rgba(192, 0, 0, 0.2); + font-weight: normal; + } +#content table tr.allowed td:nth-of-type(3) b { + background-color: rgba(0, 160, 0, 0.2); + font-weight: normal; + } \ No newline at end of file diff --git a/src/css/devtools.css b/src/css/devtools.css new file mode 100644 index 000000000..f3022e730 --- /dev/null +++ b/src/css/devtools.css @@ -0,0 +1,49 @@ +body { + font-size: 13px; + margin: 0; + overflow-y: hidden; + padding: 0; + } +#toolbar { + background-color: #eee; + border: none; + box-sizing: border-box; + height: 4em; + padding: 1em; + position: fixed; + top: 0; + width: 100%; + } +#toolbar > * { + display: inline-block; + vertical-align: middle; + } +#toolbar button { + background-color: transparent; + border: none; + cursor: pointer; + font-size: 2em; + margin: 0 0 0 1em; + vertical-align: middle; + } +#toolbar #refresh { + margin-left: 4px; + } +select { + padding: 2px 0; + font-size: 14px; + min-width: 20em; + max-width: 40em; + } +select option { + max-width: 40em; + } +#content { + border: 0; + box-sizing: border-box; + height: calc(100vh - 4em); + margin-top: 4em; + overflow-y: auto; + padding: 0; + width: 100%; + } diff --git a/src/css/popup.css b/src/css/popup.css index 1dc2251de..cb0ac5e61 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -28,22 +28,41 @@ a { font-weight: normal; margin-left: 1em; } -body > div { - background-color: transparent; +body[dir="ltr"] #panes { + direction: rtl; + } +body[dir="rtl"] #panes { + direction: ltr; + } +#panes > div { display: inline-block; position: relative; vertical-align: top; } -body > div:nth-of-type(1) { - direction: rtl; /* scroll bar to the left */ +body[dir="ltr"] #panes > div { + direction: ltr; + } +body[dir="rtl"] #panes > div { + direction: rtl; + } +#panes > div:nth-of-type(2) { overflow-y: hidden; overflow-x: hidden; + width: 0; } -body.dynamicFilteringEnabled > div:nth-of-type(1) { +body[dir="ltr"] #panes > div:nth-of-type(2) { + direction: rtl; /* scroll bar to the left */ + } +body[dir="rtl"] #panes > div:nth-of-type(2) { + direction: ltr; /* scroll bar to the right */ + } +#panes.dfEnabled > div:nth-of-type(2) { overflow-y: auto; + width: 320px; } -body > div:nth-of-type(2) { - padding: 4px 12px 0 5px; + +#panes > div:nth-of-type(1) { + padding: 4px 5px 0 5px; } p { margin: 16px 0; @@ -96,17 +115,14 @@ p { color: #444; } -#dynamicFilteringToggler { - pointer-events: none; - } -#dynamicFilteringToggler::before { +#dfToggler::before { color: gray; content: '+\202F'; cursor: pointer; - font-size: 13px; - pointer-events: auto; + font-size: 14px; + line-height: 14px; } -body.dynamicFilteringEnabled #dynamicFilteringToggler::before { +#panes.dfEnabled #dfToggler::before { content: '\2212\202F'; } @@ -142,24 +158,16 @@ body.dynamicFilteringEnabled #dynamicFilteringToggler::before { margin: 0; padding: 0; text-align: right; - width: 5px; - } -body.dynamicFilteringEnabled #dynamicFilteringContainer { - display: block; - width: auto; } #dynamicFilteringContainer > div { - background-color: transparent; + background-color: #e6e6e6; border: 0; + border-bottom: 1px solid white; direction: ltr; margin: 0; padding: 0; - width: 320px; } -body.dynamicFilteringEnabled #dynamicFilteringContainer > div { - background-color: #e6e6e6; - } -body.dynamicFilteringEnabled #dynamicFilteringContainer > div:hover { +#dynamicFilteringContainer > div:hover { background-color: #f0f0f0; } #dynamicFilteringContainer > div#privacyInfo { @@ -168,30 +176,21 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div:hover { padding: 4px 0; text-align: center; } -#dynamicFilteringContainer > div.isDomain { - margin-top: 2px; - } #dynamicFilteringContainer > div > span { background-color: transparent; border: none; - border-bottom: 1px solid white; box-sizing: border-box; - color: transparent; + color: #000; display: inline-block; height: 24px; line-height: 24px; - pointer-events: none; + overflow: hidden; position: relative; vertical-align: top; } -body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span { - color: #000; - overflow: hidden; - pointer-events: auto; - } #dynamicFilteringContainer > div > span:nth-of-type(1) { border-right: 1px solid white; - padding-right: 4px; + padding-right: 2px; text-overflow: ellipsis; width: 70%; } @@ -201,6 +200,7 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span { } #dynamicFilteringContainer > div > span:nth-of-type(3) { border-left: 1px solid white; + color: #444; cursor: pointer; text-align: center; width: 15%; @@ -208,9 +208,14 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span { #dynamicFilteringContainer > div.isDomain > span:nth-of-type(1) { font-weight: bold; } -#dynamicFilteringContainer > div > span:nth-of-type(3) { - color: #666; - pointer-events: auto; +#dynamicFilteringContainer > div.allowed > span:nth-of-type(1) { + background-color: rgba(0, 160, 0, 0.1); + } +#dynamicFilteringContainer > div.blocked > span:nth-of-type(1) { + background-color: rgba(192, 0, 0, 0.1); + } +#dynamicFilteringContainer > div.allowed.blocked > span:nth-of-type(1) { + background-color: rgba(192, 160, 0, 0.1); } #dynamicFilteringContainer > div > span.aRule { background-color: rgba(0, 160, 0, 0.3); @@ -221,17 +226,17 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span { #dynamicFilteringContainer > div > span.nRule { background-color: rgba(96, 96, 96, 0.3); } +#dynamicFilteringContainer > div > span.ownRule { + color: white; + } #dynamicFilteringContainer > div > span.aRule.ownRule { background-color: rgba(0, 160, 0, 1); - color: white; } #dynamicFilteringContainer > div > span.bRule.ownRule { background-color: rgba(192, 0, 0, 1); - color: white; } #dynamicFilteringContainer > div > span.nRule.ownRule { background-color: rgba(108, 108, 108, 1); - color: white; } #actionSelector { @@ -264,3 +269,17 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span { #dynamicFilteringContainer span.bRule #actionSelector > span:nth-of-type(3) { visibility: hidden; } +#hotspotTip { + background-color: #ffe; + border: 1px dotted #ddb; + border-radius: 5px; + height: 50vh; + opacity: 1; + padding: 4px; + position: fixed; + right: 10px; + text-align: center; + top: 25vh; + width: 20vw; + z-index: 100; + } \ No newline at end of file diff --git a/src/css/stats.css b/src/css/stats.css deleted file mode 100644 index 23ae170f5..000000000 --- a/src/css/stats.css +++ /dev/null @@ -1,86 +0,0 @@ -div { - margin: 1em 0; - } -ul { - list-style-type: none; - } -#refresh { - margin: 0 0.5em 0 4px; - display: inline-block; - vertical-align: middle; - font-size: 2em; - cursor: pointer; - } -select { - padding: 2px 0; - font-size: 14px; - min-width: 20em; - max-width: 40em; - } -select option { - max-width: 40em; - } -#requests { - margin: 2em 0 0 0; - display: none; - } -#requests.logEnabled { - display: block; - } -#requests table { - margin: 1em 0; - border: 0; - border-collapse: collapse; - min-width: 600px; - } -#requests.empty table { - display: none; - } -tr td, tr th { - border: 1px solid #aaa; - padding: 4px 6px; - white-space: pre; - } -tr.domainHeader td { - font: 16px sans-serif; - } -tr.domainHeader td span { - margin-right: 0.5em; - font-size: 14px; - color: #aaa; - cursor: pointer; - } -tr.requestEntry { - font: 12px monospace; - } -tr.requestEntry td:nth-of-type(1) { - border: 0; - background-color: white; - width: 3em; - } -tr.requestEntry td:nth-of-type(2) { - text-align: right; - } -tr.requestEntry td:nth-of-type(3), -tr.requestEntry td:nth-of-type(4) { - direction: ltr; - } -tr.logBlocked { - background-color: #fff8f8; - } -tr.logBlocked ~ tr td:nth-of-type(3) b { - padding: 2px 0; - color: #000; - background-color: rgba(255,0,0,0.1); - } -tr.logAllowed { - background-color: #f8fff8 - } -tr.logAllowed ~ tr td:nth-of-type(3) b { - padding: 2px 0; - color: #000; - background-color: rgba(0,255,0,0.2); - } -tr.logMirrored { - background-color: #ffffbb !important; - } \ No newline at end of file diff --git a/src/dashboard.html b/src/dashboard.html index 9a172dd44..4c36f6270 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -16,7 +16,6 @@ - diff --git a/src/devtool-log.html b/src/devtool-log.html new file mode 100644 index 000000000..c8ff57219 --- /dev/null +++ b/src/devtool-log.html @@ -0,0 +1,20 @@ + + + + + + +µBlock log + + +
+ + +
+
+
+ + + + + diff --git a/src/devtools.html b/src/devtools.html new file mode 100644 index 000000000..09721d152 --- /dev/null +++ b/src/devtools.html @@ -0,0 +1,25 @@ + + + + +µBlock — Statistics + + + + + + +
+ + +
+ + + + + + + + + + diff --git a/src/js/background.js b/src/js/background.js index c1816168a..4a98ab101 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -60,7 +60,6 @@ return { dynamicFilteringEnabled: false, experimentalEnabled: false, externalLists: defaultExternalLists, - logRequests: false, parseAllABPHideFilters: true, showIconBadge: true }, diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js index 0a95b0fc5..e8452f249 100644 --- a/src/js/cosmetic-filtering.js +++ b/src/js/cosmetic-filtering.js @@ -997,8 +997,14 @@ FilterContainer.prototype.removeFromSelectorCache = function(targetHostname, typ if ( this.selectorCache.hasOwnProperty(hostname) === false ) { continue; } - if ( targetHostname !== '*' && hostname !== targetHostname ) { - continue; + if ( targetHostname !== '*' ) { + if ( hostname.slice(0 - targetHostname.length) !== targetHostname ) { + continue; + } + if ( hostname.length !== targetHostname.length && + hostname.charAt(0 - targetHostname.length - 1) !== '.' ) { + continue; + } } this.selectorCache[hostname].remove(type); } diff --git a/src/js/devtool-log.js b/src/js/devtool-log.js new file mode 100644 index 000000000..38bd8a306 --- /dev/null +++ b/src/js/devtool-log.js @@ -0,0 +1,178 @@ +/******************************************************************************* + + sessbench - a Chromium browser extension to benchmark browser session. + Copyright (C) 2013 Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/sessbench + + TODO: cleanup/refactor +*/ + +/* global vAPI, uDom */ + +/******************************************************************************/ + +(function() { + +/******************************************************************************/ + +var messager = vAPI.messaging.channel('devtool-log.js'); + +var inspectedTabId = ''; +var doc = document; +var body = doc.body; +var tbody = doc.querySelector('#content tbody'); +var rowJunkyard = []; + +/******************************************************************************/ + +var renderURL = function(url, filter) { + if ( filter.charAt(0) !== 's' ) { + return url; + } + // make a regex out of the filter + var reText = filter.slice(3); + var pos = reText.indexOf('$'); + if ( pos > 0 ) { + reText = reText.slice(0, pos); + } + if ( reText === '*' ) { + reText = '\\*'; + } else { + reText = reText + .replace(/\./g, '\\.') + .replace(/\?/g, '\\?') + .replace('||', '') + .replace(/\^/g, '.') + .replace(/\*/g, '.*') + ; + } + var re = new RegExp(reText, 'gi'); + var matches = re.exec(url); + var renderedURL = url; + + if ( matches && matches[0].length ) { + renderedURL = url.slice(0, matches.index) + + '' + + url.slice(matches.index, re.lastIndex) + + '' + + url.slice(re.lastIndex); + } + + return renderedURL; +}; + +/******************************************************************************/ + +var createRow = function() { + var tr = rowJunkyard.pop(); + if ( tr ) { + tr.className = ''; + return tr; + } + tr = doc.createElement('tr'); + tr.appendChild(doc.createElement('td')); + tr.appendChild(doc.createElement('td')); + tr.appendChild(doc.createElement('td')); + return tr; +}; + +/******************************************************************************/ + +var renderLogEntry = function(entry) { + var tr = createRow(); + if ( entry.result.charAt(1) === 'b' ) { + tr.classList.add('blocked'); + } else if ( entry.result.charAt(1) === 'a' ) { + tr.classList.add('allowed'); + } + tr.cells[0].textContent = entry.result.slice(3); + tr.cells[1].textContent = entry.type; + tr.cells[2].innerHTML = renderURL(entry.url, entry.result); + tbody.insertBefore(tr, tbody.firstChild); +}; + +/******************************************************************************/ + +var renderLogBuffer = function(buffer) { + // Preserve scroll position + var height = tbody.offsetHeight; + + var n = buffer.length; + for ( var i = 0; i < n; i++ ) { + renderLogEntry(buffer[i]); + } + if ( body.scrollTop !== 0 ) { + body.scrollTop += tbody.offsetHeight - height; + } +}; + +/******************************************************************************/ + +var onBufferRead = function(buffer) { + if ( Array.isArray(buffer ) ) { + renderLogBuffer(buffer); + } + setTimeout(readLogBuffer, 1000); +}; + +/******************************************************************************/ + +// This can be called only once, at init time. After that, this will be called +// automatically. If called after init time, this will be messy, and this would +// require a bit more code to ensure no multi time out events. + +var readLogBuffer = function() { + messager.send({ what: 'readLogBuffer', tabId: inspectedTabId }, onBufferRead); +}; + +/******************************************************************************/ + +var clearBuffer = function() { + var rows = tbody.rows; + var row; + var i = rows.length; + while ( i-- ) { + row = rows[i]; + row.parentNode.removeChild(row); + rowJunkyard.push(row); + } +}; + +/******************************************************************************/ + +var reloadTab = function() { + messager.send({ what: 'reloadTab', tabId: inspectedTabId }); +}; + +/******************************************************************************/ + +uDom.onLoad(function() { + // Extract the tab id of the page we need to pull the log + var matches = window.location.search.match(/[\?&]tabId=([^&]+)/); + if ( matches && matches.length === 2 ) { + inspectedTabId = matches[1]; + } + + readLogBuffer(); + + uDom('#reload').on('click', reloadTab); + uDom('#clear').on('click', clearBuffer); +}); + +/******************************************************************************/ + +})(); diff --git a/src/js/devtools.js b/src/js/devtools.js new file mode 100644 index 000000000..809eae93e --- /dev/null +++ b/src/js/devtools.js @@ -0,0 +1,98 @@ +/******************************************************************************* + + µBlock - a Chromium browser extension to block requests. + Copyright (C) 2014 Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +/* jshint bitwise: false */ +/* global vAPI, uDom */ + +/******************************************************************************/ + +(function() { + +'use strict'; + +/******************************************************************************/ + +var messager = vAPI.messaging.channel('stats.js'); + +/******************************************************************************/ + +var renderPageSelector = function(targetTabId) { + var selectedTabId = targetTabId || uDom('#pageSelector').val(); + var onTabReceived = function(tabId, tabTitle) { + uDom('#pageSelector').append('