From 40a17f43b3e338d8e708ab61d383602946c9e115 Mon Sep 17 00:00:00 2001 From: Zelgadis Date: Mon, 23 Feb 2009 15:31:00 +0100 Subject: [PATCH] Initial commit. Version 0.5.0 --- chrome.manifest | 2 + components/minimalist.js | 178 +++++++++++++++++++++++++++++++++++++ content/minimalist.js | 63 +++++++++++++ content/minimalist.xul | 3 + defaults/preferences/minimalist.js | 19 ++++ install.rdf | 16 ++++ minimalist_0.5.0.xpi | Bin 0 -> 4849 bytes 7 files changed, 281 insertions(+) create mode 100644 chrome.manifest create mode 100644 components/minimalist.js create mode 100644 content/minimalist.js create mode 100644 content/minimalist.xul create mode 100644 defaults/preferences/minimalist.js create mode 100644 install.rdf create mode 100644 minimalist_0.5.0.xpi diff --git a/chrome.manifest b/chrome.manifest new file mode 100644 index 0000000..84f4c46 --- /dev/null +++ b/chrome.manifest @@ -0,0 +1,2 @@ +content minimalist content/ +overlay chrome://browser/content/browser.xul chrome://minimalist/content/minimalist.xul \ No newline at end of file diff --git a/components/minimalist.js b/components/minimalist.js new file mode 100644 index 0000000..7e449c9 --- /dev/null +++ b/components/minimalist.js @@ -0,0 +1,178 @@ +function NSGetModule(compMgr, fileSpec) +{ + // Constants // + const settings = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch) + const urlParser = Components.classes['@mozilla.org/network/standard-url;1'].getService(Components.interfaces.nsIURI) + const whiteList = {'chrome': true, 'resource': true} + const hostRE = /^(?:\d{1,3}\.){3}\d{1,3}|[\w\-]{3,}(?=(?:\.[a-z]{2})*\.\w{2,}$)/ + const contentRE = /^(?:text\/html|application\/xhtml\+xml)/ + const cacheRE = /^(?:text|image|multipart)\/|^application\/(?:x-)?(?:javascript|json)/ + const ACCEPT = Components.interfaces.nsIContentPolicy.ACCEPT + const REJECT = Components.interfaces.nsIContentPolicy.REJECT_SERVER + var exceptions = { } + var filterLevel = 3 + + // Implementation: content-policy // + function getDomainName(URL) + { + hostName = hostRE.exec(URL.host) + return hostName ? hostName[0].toLowerCase() : URL.host + } + + function isImageLink(node) + { + return node instanceof Components.interfaces.nsIDOMHTMLImageElement && + node.parentNode instanceof Components.interfaces.nsIDOMHTMLAnchorElement + } + + function lastMeasure(node, targetURL) + { + if (filterLevel > 2 && isImageLink(node)) { + return ACCEPT + } else + return ACCEPT + } + + function shouldLoad(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) + { + if (filterLevel < 1 || context instanceof Components.interfaces.nsIDOMXULElement || requestOrigin == null || + requestOrigin.scheme in whiteList || contentLocation.scheme in whiteList) + return ACCEPT + + sourceHost = getDomainName(requestOrigin) + destHost = getDomainName(contentLocation) + + if (filterLevel > 1 && isImageLink(context)) { + urlParser.spec = context.parentNode.href + if (getDomainName(urlParser) != sourceHost) + return REJECT + } + + if (sourceHost == destHost) + return lastMeasure(context, contentLocation) + + exceptHosts = exceptions[sourceHost] + if (exceptHosts && destHost in exceptHosts) + return lastMeasure(context, contentLocation) + else + return REJECT + } + + // Implementation: http-on-modify-request // + function getRequestHeader(channel, tag) + { + try { return channel.getRequestHeader(tag) } + catch (e) { return false } + } + + function getResponseHeader(channel, tag) + { + try { return channel.getResponseHeader(tag) } + catch (e) { return false } + } + + function observe(subject, topic, data) + { + switch (topic) + { + case 'http-on-modify-request': + if (subject) { + httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel) + httpChannel.setRequestHeader('If-Modified-Since', '', false) + httpChannel.setRequestHeader('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) ' + + 'Gecko/2009011913 Firefox/3.0.6 ', false) + + if (httpReferer = getRequestHeader(httpChannel, 'Referer')) { + urlParser.spec = httpReferer + httpReferer = getDomainName(urlParser) + urlParser.spec = 'http://' + getRequestHeader(httpChannel, 'Host') + + if (httpReferer != getDomainName(urlParser)) + httpChannel.setRequestHeader('Referer', urlParser.spec, false) + } + } + break + + case 'http-on-examine-response': + if (subject) { + httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel) + httpChannel.setResponseHeader('Age', '', false) + httpChannel.setResponseHeader('Cache-Control', '', false) + httpChannel.setResponseHeader('Date', '', false) + httpChannel.setResponseHeader('ETag', '', false) + httpChannel.setResponseHeader('Last-Modified', '', false) + httpChannel.setResponseHeader('Pragma', '', false) + httpChannel.setResponseHeader('Vary', '', false) + + if (contentType = getResponseHeader(httpChannel, 'Content-Type')) { + if (contentType.match(contentRE)) + httpChannel.setResponseHeader('Expires', new Date( Date.now() + 120000 ).toGMTString(), false) + else { + contentLength = getResponseHeader(httpChannel, 'Content-Length') + if (!contentLength || parseInt(contentLength) > 2097152 || !contentType.match(cacheRE)) + httpChannel.setResponseHeader('Expires', 'Thu, 01 Jan 1970 00:00:00 GMT', false) + else + httpChannel.setResponseHeader('Expires', 'Sun, 07 Feb 2106 06:28:15 GMT', false) + } + } + } + break + + case 'nsPref:changed': + path = data.split('.') + switch (path[2]) + { + case 'whitelist': + srcHost = path[3] + dstHost = settings.getCharPref(data).split(',') + + if (dstHost.length > 0) { + exceptions[srcHost] = { } + for (i in dstHost) + exceptions[srcHost][dstHost[i]] = true + } else + delete exceptions[srcHost] + break + + case 'level': + filterLevel = settings.getIntPref(data) + break + } + break + } + } + + // XPCOM registration // + Components.utils.import('resource://gre/modules/XPCOMUtils.jsm') + + function Minimalist() { + this.wrappedJSObject = this + observer = Components.classes['@mozilla.org/observer-service;1'].getService(Components.interfaces.nsIObserverService) + observer.addObserver(this, 'http-on-modify-request', false) + observer.addObserver(this, 'http-on-examine-response', false) + settings.QueryInterface(Components.interfaces.nsIPrefBranch2) + settings.addObserver('extensions.minimalist.', this, false) + + entries = settings.getChildList('extensions.minimalist.whitelist', {}) + for (i in entries) { + entry = entries[i].split('.')[3] + exceptions[entry] = {} + + values = settings.getCharPref(entries[i]).split(',') + for (j in values) + exceptions[entry][values[j]] = true + } + } + Minimalist.prototype = { + classDescription: 'Minimalist', + classID: Components.ID('{124b1de7-bd8a-4a41-a04a-9d40070a0b3a}'), + contractID: '@zelgadis.jp/minimalist;1', + _xpcom_categories: [{category: 'content-policy'}], + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIContentPolicy, Components.interfaces.nsIObserver]), + shouldLoad: shouldLoad, + shouldProcess: function() { return ACCEPT }, + observe: observe + } + + return XPCOMUtils.generateModule([Minimalist]) +} \ No newline at end of file diff --git a/content/minimalist.js b/content/minimalist.js new file mode 100644 index 0000000..91486ee --- /dev/null +++ b/content/minimalist.js @@ -0,0 +1,63 @@ +(function() { + function nodeFilter(node) { + if (!(node.parentNode.tagName in ignore)) + return NodeFilter.FILTER_ACCEPT + } + + function metaHandler(event) { + metaTags = event.target.getElementsByTagName('meta') + + for (i in metaTags) { + metaTag = metaTags[i] + + if (metaTag.httpEquiv.toLowerCase() == 'refresh') { + match = metaRE.exec(metaTag.content) + + if (match != null) { + srcURL.spec = event.target.location.href + dstURL.spec = event.target.location.href + srcURL.spec = srcURL.resolve(match[1]) + + if (!srcURL.equals(dstURL)) + event.target.location.replace(dstURL.spec) + } + } + } + + /*nodeIterator = document.createNodeIterator(event.target, NodeFilter.SHOW_TEXT, { acceptNode: nodeFilter }, true) + while (currentNode = nodeIterator.nextNode()) { + splitData = currentNode.data.split(urlRE) + + if (splitData.length > 1) { + isText = true + lastNode = currentNode + parentNode = currentNode.parentNode + + while (token = splitData.pop()) { + if (isText) { + isText = false + newNode = document.createTextNode(token) + } else { + isText = true + newNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'html:a') + newNode.appendChild(document.createTextNode(token)) + + if (token.substr(0, 4) == 'www.') + token = 'http://' + token + newNode.setAttribute('href', token) + } + parentNode.insertBefore(newNode, lastNode) + lastNode = newNode + } + parentNode.removeChild(currentNode) + } + }*/ + } + + var metaRE = /url=(.+)/i + var urlRE = /((?:h(?:tt|xx)ps?|ftp|ed2k):\/\/\S{6,}|www\.\S{6,})/i + var ignore = {'A': true, 'HEAD': true, 'META': true, 'SCRIPT': true, 'STYLE': true, 'TITLE': true} + var srcURL = Components.classes['@mozilla.org/network/standard-url;1'].getService(Components.interfaces.nsIURI) + var dstURL = srcURL.clone() + getBrowser().addEventListener('DOMContentLoaded', metaHandler, false) +})() \ No newline at end of file diff --git a/content/minimalist.xul b/content/minimalist.xul new file mode 100644 index 0000000..26be150 --- /dev/null +++ b/content/minimalist.xul @@ -0,0 +1,3 @@ + +