gorhill
10 years ago
6 changed files with 535 additions and 10 deletions
-
118src/css/logger-ui.css
-
22src/css/popup.css
-
63src/js/browsercache.js
-
309src/js/logger-ui.js
-
25src/logger-ui.html
-
8src/popup.html
@ -0,0 +1,118 @@ |
|||||
|
body { |
||||
|
border: 0; |
||||
|
box-sizing: border-box; |
||||
|
-moz-box-sizing: border-box; |
||||
|
margin: 0; |
||||
|
overflow-x: hidden; |
||||
|
padding: 0; |
||||
|
white-space: nowrap; |
||||
|
width: 100%; |
||||
|
} |
||||
|
#toolbar { |
||||
|
background-color: white; |
||||
|
border: 0; |
||||
|
box-sizing: border-box; |
||||
|
height: 40px; |
||||
|
left: 0; |
||||
|
margin: 0; |
||||
|
padding: 0 1em; |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
width: 100%; |
||||
|
} |
||||
|
#toolbar .button { |
||||
|
background-color: white; |
||||
|
border: none; |
||||
|
box-sizing: border-box; |
||||
|
cursor: pointer; |
||||
|
display: inline-block; |
||||
|
font-size: 20px; |
||||
|
margin: 0; |
||||
|
padding: 8px; |
||||
|
} |
||||
|
#toolbar .button:hover { |
||||
|
background-color: #eee; |
||||
|
} |
||||
|
body.filterOff #toolbar #filterButton { |
||||
|
opacity: 0.25; |
||||
|
} |
||||
|
#filterExpression.bad { |
||||
|
background-color: #fee; |
||||
|
} |
||||
|
#maxEntries { |
||||
|
margin-left: 3em; |
||||
|
} |
||||
|
input:focus { |
||||
|
background-color: #ffe; |
||||
|
} |
||||
|
#content { |
||||
|
margin-top: 40px; |
||||
|
} |
||||
|
#content table { |
||||
|
border: 0; |
||||
|
border-collapse: collapse; |
||||
|
direction: ltr; |
||||
|
font: 12px monospace; |
||||
|
width: 100%; |
||||
|
} |
||||
|
#content table tr { |
||||
|
background-color: #fafafa; |
||||
|
} |
||||
|
#content table tr:nth-of-type(2n+1) { |
||||
|
background-color: #eee; |
||||
|
} |
||||
|
#content table tr.doc { |
||||
|
background-color: #666; |
||||
|
color: white; |
||||
|
text-align: center; |
||||
|
} |
||||
|
#content table tr.doc > td:nth-of-type(2) { |
||||
|
padding: 1em 0; |
||||
|
white-space: normal; |
||||
|
word-break: break-all; |
||||
|
word-wrap: break-word; |
||||
|
} |
||||
|
#content table tr.cat_info { |
||||
|
color: #00a; |
||||
|
} |
||||
|
#content table tr.blocked { |
||||
|
color: #c00; |
||||
|
} |
||||
|
/* |
||||
|
#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; |
||||
|
padding: 3px; |
||||
|
vertical-align: top; |
||||
|
} |
||||
|
#content table tr td:nth-of-type(1) { |
||||
|
text-align: center; |
||||
|
white-space: pre; |
||||
|
width: 8em; |
||||
|
} |
||||
|
#content table tr td:nth-of-type(2) { |
||||
|
white-space: pre; |
||||
|
width: 2em; |
||||
|
} |
||||
|
#content table tr td:nth-of-type(3) { |
||||
|
white-space: pre; |
||||
|
width: 8em; |
||||
|
} |
||||
|
#content table tr td:nth-of-type(4) { |
||||
|
border-right: none; |
||||
|
white-space: normal; |
||||
|
word-break: break-all; |
||||
|
word-wrap: break-word; |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
uMatrix - a Chromium browser extension to black/white list requests. |
||||
|
Copyright (C) 2015 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/uMatrix
|
||||
|
*/ |
||||
|
|
||||
|
/* global µMatrix */ |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
(function() { |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// Browser data jobs
|
||||
|
|
||||
|
var clearCache = function() { |
||||
|
setTimeout(clearCache, 15 * 60 * 1000); |
||||
|
|
||||
|
var µm = µMatrix; |
||||
|
if ( !µm.userSettings.clearBrowserCache ) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
µm.clearBrowserCacheCycle -= 15; |
||||
|
if ( µm.clearBrowserCacheCycle > 0 ) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
µm.clearBrowserCacheCycle = µm.userSettings.clearBrowserCacheAfter; |
||||
|
µm.browserCacheClearedCounter++; |
||||
|
|
||||
|
vAPI.browserCache.clearByTime(0); |
||||
|
|
||||
|
µm.logger.writeOne('', 'info', 'browser cache cleared'); |
||||
|
|
||||
|
//console.debug('clearBrowserCacheCallback()> vAPI.browserCache.clearByTime() called');
|
||||
|
}; |
||||
|
|
||||
|
setTimeout(clearCache, 15 * 60 * 1000); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(); |
||||
|
|
||||
|
/******************************************************************************/ |
@ -0,0 +1,309 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
uMatrix - a browser extension to benchmark browser session. |
||||
|
Copyright (C) 2015 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 |
||||
|
*/ |
||||
|
|
||||
|
/* jshint boss: true */ |
||||
|
/* global vAPI, uDom */ |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
(function() { |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var messager = vAPI.messaging.channel('logger-ui.js'); |
||||
|
|
||||
|
var inspectedTabId = ''; |
||||
|
var maxEntries = 0; |
||||
|
var doc = document; |
||||
|
var body = doc.body; |
||||
|
var tbody = doc.querySelector('#content tbody'); |
||||
|
var trJunkyard = []; |
||||
|
var tdJunkyard = []; |
||||
|
var firstVarDataCol = 1; |
||||
|
var lastVarDataCol = 3; |
||||
|
|
||||
|
var prettyRequestTypes = { |
||||
|
'main_frame': 'doc', |
||||
|
'stylesheet': 'css', |
||||
|
'sub_frame': 'frame', |
||||
|
'xmlhttprequest': 'xhr' |
||||
|
}; |
||||
|
|
||||
|
var timeOptions = { |
||||
|
month: 'short', |
||||
|
day: '2-digit', |
||||
|
hour: '2-digit', |
||||
|
minute: '2-digit', |
||||
|
second: '2-digit' |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var createCell = function() { |
||||
|
var td = tdJunkyard.pop(); |
||||
|
if ( td ) { |
||||
|
return td; |
||||
|
} |
||||
|
return doc.createElement('td'); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var createRow = function(entry) { |
||||
|
var tr = trJunkyard.pop(); |
||||
|
if ( tr ) { |
||||
|
tr.className = ''; |
||||
|
} 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'); |
||||
|
} |
||||
|
var i = 1, span = 1; |
||||
|
for (;;) { |
||||
|
td = tr.cells[index]; |
||||
|
if ( td === undefined ) { |
||||
|
td = createCell(); |
||||
|
tr.appendChild(td); |
||||
|
} |
||||
|
if ( i === lastVarDataCol ) { |
||||
|
break; |
||||
|
} |
||||
|
if ( entry['d' + i] === undefined ) { |
||||
|
span += 1; |
||||
|
} else { |
||||
|
if ( span !== 1 ) { |
||||
|
td.setAttribute('colspan', span); |
||||
|
} else { |
||||
|
td.removeAttribute('colspan'); |
||||
|
} |
||||
|
index += 1; |
||||
|
span = 1; |
||||
|
} |
||||
|
i += 1; |
||||
|
} |
||||
|
if ( span !== 1 ) { |
||||
|
td.setAttribute('colspan', span); |
||||
|
} else { |
||||
|
td.removeAttribute('colspan'); |
||||
|
} |
||||
|
index += 1; |
||||
|
while ( td = tr.cells[index] ) { |
||||
|
tdJunkyard.push(tr.removeChild(td)); |
||||
|
} |
||||
|
return tr; |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var createGap = function(url) { |
||||
|
var tr = createRow({ d0: '' }); |
||||
|
tr.classList.add('doc'); |
||||
|
tr.cells[firstVarDataCol].textContent = url; |
||||
|
tbody.insertBefore(tr, tbody.firstChild); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var renderLogEntry = function(entry) { |
||||
|
var tr = createRow(entry); |
||||
|
|
||||
|
tr.classList.add('tab_' + entry.tab); |
||||
|
tr.classList.add('cat_' + entry.cat); |
||||
|
|
||||
|
var time = new Date(entry.tstamp); |
||||
|
tr.cells[0].textContent = time.toLocaleString('fullwide', timeOptions); |
||||
|
|
||||
|
switch ( entry.cat ) { |
||||
|
case 'info': |
||||
|
tr.cells[firstVarDataCol].textContent = entry.d0; |
||||
|
break; |
||||
|
|
||||
|
case 'net': |
||||
|
// If the request is that of a root frame, insert a gap in the table
|
||||
|
// in order to visually separate entries for different documents.
|
||||
|
if ( entry.d1 === 'doc' ) { |
||||
|
createGap(entry.d2); |
||||
|
} |
||||
|
if ( entry.d0 ) { |
||||
|
tr.classList.add('blocked'); |
||||
|
tr.cells[1].textContent = '---'; |
||||
|
} else { |
||||
|
tr.cells[1].textContent = ''; |
||||
|
} |
||||
|
tr.cells[2].textContent = (prettyRequestTypes[entry.d1] || entry.d1) + '\t'; |
||||
|
tr.cells[3].textContent = entry.d2 + '\t'; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
tbody.insertBefore(tr, tbody.firstChild); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var renderLogBuffer = function(response) { |
||||
|
var buffer = response.entries; |
||||
|
if ( buffer.length === 0 ) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Preserve scroll position
|
||||
|
var height = tbody.offsetHeight; |
||||
|
|
||||
|
var n = buffer.length; |
||||
|
for ( var i = 0; i < n; i++ ) { |
||||
|
renderLogEntry(buffer[i]); |
||||
|
} |
||||
|
|
||||
|
// Prevent logger from growing infinitely and eating all memory. For
|
||||
|
// instance someone could forget that it is left opened for some
|
||||
|
// dynamically refreshed pages.
|
||||
|
truncateLog(maxEntries); |
||||
|
|
||||
|
var yDelta = tbody.offsetHeight - height; |
||||
|
if ( yDelta === 0 ) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Chromium:
|
||||
|
// body.scrollTop = good value
|
||||
|
// body.parentNode.scrollTop = 0
|
||||
|
if ( body.scrollTop !== 0 ) { |
||||
|
body.scrollTop += yDelta; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Firefox:
|
||||
|
// body.scrollTop = 0
|
||||
|
// body.parentNode.scrollTop = good value
|
||||
|
var parentNode = body.parentNode; |
||||
|
if ( parentNode && parentNode.scrollTop !== 0 ) { |
||||
|
parentNode.scrollTop += yDelta; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var truncateLog = function(size) { |
||||
|
if ( size === 0 ) { |
||||
|
size = 25000; |
||||
|
} |
||||
|
size = Math.min(size, 25000); |
||||
|
var tr; |
||||
|
while ( tbody.childElementCount > size ) { |
||||
|
tr = tbody.lastElementChild; |
||||
|
trJunkyard.push(tbody.removeChild(tr)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var onBufferRead = function(response) { |
||||
|
renderLogBuffer(response); |
||||
|
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: 'readMany', tabId: inspectedTabId }, onBufferRead); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var clearBuffer = function() { |
||||
|
var tr; |
||||
|
while ( tbody.firstChild !== null ) { |
||||
|
tr = tbody.lastElementChild; |
||||
|
trJunkyard.push(tbody.removeChild(tr)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var reloadTab = function() { |
||||
|
messager.send({ what: 'reloadTab', tabId: inspectedTabId }); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
var onMaxEntriesChanged = function() { |
||||
|
var raw = uDom(this).val(); |
||||
|
try { |
||||
|
maxEntries = parseInt(raw, 10); |
||||
|
if ( isNaN(maxEntries) ) { |
||||
|
maxEntries = 0; |
||||
|
} |
||||
|
} catch (e) { |
||||
|
maxEntries = 0; |
||||
|
} |
||||
|
|
||||
|
messager.send({ |
||||
|
what: 'userSettings', |
||||
|
name: 'requestLogMaxEntries', |
||||
|
value: maxEntries |
||||
|
}); |
||||
|
|
||||
|
truncateLog(maxEntries); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
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]; |
||||
|
} |
||||
|
|
||||
|
var onSettingsReady = function(settings) { |
||||
|
maxEntries = settings.requestLogMaxEntries || 0; |
||||
|
uDom('#maxEntries').val(maxEntries || ''); |
||||
|
}; |
||||
|
messager.send({ what: 'getUserSettings' }, onSettingsReady); |
||||
|
|
||||
|
readLogBuffer(); |
||||
|
|
||||
|
uDom('#reload').on('click', reloadTab); |
||||
|
uDom('#clear').on('click', clearBuffer); |
||||
|
uDom('#maxEntries').on('change', onMaxEntriesChanged); |
||||
|
}); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(); |
@ -0,0 +1,25 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/logger-ui.css"> |
||||
|
<title>uMatrix log</title> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="toolbar"> |
||||
|
<span id="reload" class="button fa"></span> |
||||
|
<span id="clear" class="button fa"></span> |
||||
|
<span id="filterButton" class="button fa"></span><input id="filterExpression" type="text" placeholder="logFilterPrompt"> |
||||
|
<input id="maxEntries" type="text" size="5" title="logMaxEntriesTip"> |
||||
|
</div> |
||||
|
<div id="content"> |
||||
|
<table><tbody></tbody></table> |
||||
|
</div> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/logger-ui.js"></script> |
||||
|
</body> |
||||
|
</html> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue