1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
11 var EXPORTED_SYMBOLS = [
14 let {utils:Cu, classes:Cc, interfaces:Ci, results:Cr} = Components;
17 //////////////////////////////////////////////////////////////////////////////
18 Cu.import("resource://gre/modules/Services.jsm");
20 //////////////////////////////////////////////////////////////////////////////
21 Cu.import("chrome://k8-imago-code/content/modules/utils.js");
22 Cu.import(MODULE_PATH+"debuglog.js");
23 Cu.import(MODULE_PATH+"prefs.js");
24 Cu.import(MODULE_PATH+"tamper.js");
25 Cu.import(MODULE_PATH+"stoplist.js");
26 Cu.import(MODULE_PATH+"imgreload.js");
27 Cu.import(MODULE_PATH+"hazard.js");
28 Cu.import(MODULE_PATH+"rule-engine.js");
31 //////////////////////////////////////////////////////////////////////////////
32 // init some functions from window
35 registerWindowHook("load", function (win) {
39 registerWindowHook("unload", function (win) {
44 //////////////////////////////////////////////////////////////////////////////
45 let tldsvc = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
48 //////////////////////////////////////////////////////////////////////////////
49 let imagectRE = /^image\//;
52 let httpRequestObserver = {
53 QueryInterface: function (aIID) {
54 if (aIID.equals(Ci.nsIObserver) || aIID.equals(Ci.nsISupports)) return this;
55 throw Components.results.NS_NOINTERFACE;
58 observe: function (aSubject, aTopic, aData) {
59 if (!(aSubject instanceof Ci.nsIHttpChannel)) return;
61 if (aTopic === "http-on-examine-response") {
62 // aSubject is request object
63 let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
65 let dw = getDomWindowForChannel(httpChannel), bro = null;
67 bro = getBrowserForDomWindow(dw);
69 if (PREFS.debugLog) conlog("[", httpChannel.URI.spec, "] browser: ", bro.currentURI.spec);
71 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "] NO browser");
75 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "] NO dom window");
78 let docURI = bro.currentURI.spec;
80 // process redirects for whitelisted and blacklisted images
81 if (httpChannel.responseStatus >= 300 && httpChannel.responseStatus <= 399) {
82 let wl = isUnblockedImage(httpChannel.URI, docURI);
83 let bl = isBlockedImage(httpChannel.URI, docURI);
85 imageLoaderActivated(httpChannel.URI, docURI);
86 if (PREFS.debugLog) conlog("***GOT IMAGE REDIRECT FOR ["+httpChannel.URI.spec+"]! responseStatus="+httpChannel.responseStatus);
87 let loc = httpChannel.getResponseHeader("Location");
89 if (PREFS.debugLog) conlog("***REDIRECT TO: ["+loc+"]");
91 unblockImage(loc, docURI);
92 registerManualReloadRedirectURL(httpChannel.URI.spec, loc);
94 blockImage(loc, docURI);
100 let ctype = httpChannel.contentType;
102 if (!imagectRE.test(ctype) /*&& ctype !== "application/octet-stream"*/) {
103 // if we got a non-redirecting reply, reset image status
104 resetImageStatus(httpChannel.URI, docURI);
105 //conlog("ctype: ", ctype);
109 // intercept and count
110 if (Math.floor(httpChannel.responseStatus/100) === 2) {
111 imageLoaderActivated(httpChannel.URI, docURI);
112 let doSizeBlockInTamper = false;
114 if (PREFS.debugLog) conlog("*** CHECKING [", httpChannel.URI.spec, "]...");
115 let isoctet = false/*ctype === "application/octet-stream"*/;
117 if (isUnblockedImage(httpChannel.URI, docURI)) {
118 if (PREFS.debugLog) conlog("*** UNBLOCKED [", httpChannel.URI.spec, "]...");
122 let blacklisted = (isBlockedImage(httpChannel.URI, docURI));
123 // global black/white lists
125 //TODO: list priorities
126 // this can pappen for "chrome:", for exampe
127 let host = (httpChannel.URI.host ? httpChannel.URI.host : "nohost");
128 if (WHITE_HOSTS[host]) {
130 if (PREFS.debugLog) conlog("*** WHITE HOST [", httpChannel.URI.spec, "]...");
133 if (host in BLACK_HOSTS) blacklisted = BLACK_HOSTS[host];
135 if (!blacklisted && dw && PREFS.maxTotalBytesForDoc > 0) {
137 let ctlen = parseInt(httpChannel.getResponseHeader("Content-Length"), 10);
138 if (isNaN(ctlen)) doSizeBlockInTamper = true;
139 if (!isNaN(ctlen) && ctlen > 0) {
140 let isize = getByteCounterForDomWindow(dw)+ctlen;
141 if (isize >= PREFS.maxTotalBytesForDoc) {
142 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "]: blacklisted due to bytes limit: isize="+isize+"; max="+PREFS.maxTotalBytesForDoc+"; ctlen="+ctlen);
145 setByteCounterForDomWindow(dw, isize);
149 // httpChannel.getResponseHeader can throw when download is blocked (like font), just get out of here
156 // check if we have too much images for this DOM window
157 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "] searching for rule...");
158 rule = getRuleForURI(httpChannel.URI, bro.currentURI);
160 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "] rule: ", rule);
161 if (rule.stopAction) {
162 if (rule.action === "deny") {
163 if (PREFS.debugLog) conlog("*** [", httpChannel.URI.spec, "] blocked by 'deny' rule!");
169 //conlog("bl: [", httpChannel.URI.spec, "]: ", blacklisted);
170 // check for 1st-party images
171 if (!blacklisted && PREFS.allowFirstPartyImages && !bro.currentURI.equals(httpChannel.URI)) {
172 // i've seen "Error: NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIURI.host]" there, so...
174 if (tldsvc.getBaseDomain(bro.currentURI) === tldsvc.getBaseDomain(httpChannel.URI)) {
175 if (PREFS.debugLog) conlog(httpChannel.URI.spec, ": first-party!");
180 //if (PREFS.debugLog) conlog("counting: ", httpChannel.URI.spec);
181 let nlst = new ImgDetectListener(isoctet, blacklisted, doSizeBlockInTamper);
183 nlst.mainURI = bro.currentURI;
184 aSubject.QueryInterface(Ci.nsITraceableChannel);
185 nlst.olst = aSubject.setNewListener(nlst);
187 // onStartRequest() and onStopRequest() will be called anyway, and
188 // our tamper will process that correctly for blacklisted images
189 if (blacklisted) aSubject.cancel(Cr.NS_BINDING_ABORTED);
191 if (PREFS.debugLog) conlog("WTF: ", httpChannel.URI.spec, " (", httpChannel.responseStatus, ")");
192 //aSubject.cancel(Cr.NS_BINDING_ABORTED);
193 resetImageStatus(httpChannel.URI, docURI);
195 } else if (aTopic === "http-on-modify-request") {
196 let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
197 let url = httpChannel.URI.spec;
198 // WARNING! `isManualReloadURL()` modifies internal URL cache (i.e. it is destructive!)
199 if (isManualReloadURL(url)) {
200 // ah, ok, i took time from rfc
201 httpChannel.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT", false);
202 httpChannel.setRequestHeader("ETag", "", false);
203 //delete reloadUrlList[url]; // no need to, `isManualReloadURL()` will do it for us
210 //////////////////////////////////////////////////////////////////////////////
211 let osvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
212 osvc.addObserver(httpRequestObserver, "http-on-examine-response", false);
213 osvc.addObserver(httpRequestObserver, "http-on-modify-request", false);