Index: lib/child/bootstrap.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/lib/child/bootstrap.js
@@ -0,0 +1,92 @@
+/*
+ * This file is part of Adblock Plus ,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see .
+ */
+
+(function()
+{
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const Cr = Components.results;
+ const Cu = Components.utils;
+
+ let {Loader, main, unload} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
+
+ let loader = null;
+
+ let shutdownHandlers = [];
+ let onShutdown =
+ {
+ done: false,
+ add: function(handler)
+ {
+ if (shutdownHandlers.indexOf(handler) < 0)
+ shutdownHandlers.push(handler);
+ },
+ remove: function(handler)
+ {
+ let index = shutdownHandlers.indexOf(handler);
+ if (index >= 0)
+ shutdownHandlers.splice(index, 1);
+ }
+ };
+
+ addMessageListener("AdblockPlus:Info", init);
+ addMessageListener("AdblockPlus:Shutdown", shutdown);
+
+ function init(message)
+ {
+ removeMessageListener("AdblockPlus:Info", init);
+
+ let info = message.data;
+ loader = Loader({
+ paths: {
+ "": info.addonRoot + "lib/"
+ },
+ globals: {
+ Components, Cc, Ci, Cu, Cr, atob, btoa, onShutdown,
+ addMessageListener, removeMessageListener, sendAsyncMessage, sendSyncMessage
+ },
+ modules: {"info": info},
+ id: info.addonID
+ });
+ onShutdown.add(() => unload(loader, "disable"))
+
+ main(loader, "child/main");
+ }
+
+ function shutdown(message)
+ {
+ if (message.data == Components.stack.filename)
+ {
+ removeMessageListener("AdblockPlus:Shutdown", shutdown);
+
+ onShutdown.done = true;
+ for (let i = shutdownHandlers.length - 1; i >= 0; i --)
+ {
+ try
+ {
+ shutdownHandlers[i]();
+ }
+ catch (e)
+ {
+ Cu.reportError(e);
+ }
+ }
+ shutdownHandlers = null;
+ }
+ }
+})();
+
Index: lib/child/main.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/lib/child/main.js
@@ -0,0 +1,18 @@
+/*
+ * This file is part of Adblock Plus ,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see .
+ */
+
+require("elemHideHitRegistration");
Index: lib/contentPolicy.js
===================================================================
--- a/lib/contentPolicy.js
+++ b/lib/contentPolicy.js
@@ -47,17 +47,17 @@ let nonVisualTypes = ["SCRIPT", "STYLESH
* Randomly generated class name, to be applied to collapsed nodes.
*/
let collapsedClass = "";
/**
* Public policy checking functions and auxiliary objects
* @class
*/
-let Policy = exports.Policy =
+var Policy = exports.Policy =
{
/**
* Map of content type identifiers by their name.
* @type Object
*/
type: {},
/**
@@ -354,17 +354,17 @@ let Policy = exports.Policy =
}
};
Policy.init();
/**
* Actual nsIContentPolicy and nsIChannelEventSink implementation
* @class
*/
-let PolicyImplementation =
+var PolicyImplementation =
{
classDescription: "Adblock Plus content policy",
classID: Components.ID("cfeaabe6-1dd1-11b2-a0c6-cb5c268894c9"),
contractID: "@adblockplus.org/abp/policy;1",
xpcom_categories: ["content-policy", "net-channel-event-sinks"],
/**
* Registers the content policy on startup.
Index: lib/elemHide.js
===================================================================
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -21,17 +21,16 @@
Cu.import("resource://gre/modules/Services.jsm");
let {Utils} = require("utils");
let {IO} = require("io");
let {Prefs} = require("prefs");
let {ElemHideException} = require("filterClasses");
let {FilterNotifier} = require("filterNotifier");
-let {AboutHandler} = require("elemHideHitRegistration");
/**
* Lookup table, filters by their associated key
* @type Object
*/
let filterByKey = Object.create(null);
/**
@@ -76,25 +75,32 @@ let ElemHide = exports.ElemHide =
*/
applied: false,
/**
* Called on module startup.
*/
init: function()
{
+ let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+ .getService(Ci.nsIMessageListenerManager);
+ let hitHandler = (message => {
+ let result = ElemHide.shouldHide(message.data);
+ let target = message.target.QueryInterface(Ci.nsIMessageSender);
+ target.sendAsyncMessage(message.data.responseMessage, result);
+ });
+ messageManager.addMessageListener("AdblockPlus:ElemHideHit", hitHandler);
+ onShutdown.add(() => messageManager.removeMessageListener("AdblockPlus:ElemHideHit", hitHandler));
+
Prefs.addListener(function(name)
{
if (name == "enabled")
ElemHide.apply();
});
- onShutdown.add(function()
- {
- ElemHide.unapply();
- });
+ onShutdown.add(() => ElemHide.unapply());
let styleFile = IO.resolveFilePath(Prefs.data_directory);
styleFile.append("elemhide.css");
styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL);
},
/**
* Removes all known filters
@@ -184,16 +190,64 @@ let ElemHide = exports.ElemHide =
for (let i = list.length - 1; i >= 0; i--)
if (list[i].isActiveOnDomain(docDomain))
return list[i];
return null;
},
/**
+ * Processes an element hiding hit
+ * @param {String} message.key
+ * key of the matching element hiding rule
+ * @param {Object[]} message.frames
+ * information required to reconstruct frame
+ * data for the hit
+ * @return {Boolean}
+ */
+ shouldHide: function(message)
+ {
+ let filter = ElemHide.getFilterByKey(message.key);
+ if (!filter || !message.frames.length)
+ return false;
+
+ let fakeFrame = null;
+ for (let i = message.frames.length - 1; i >= 0; i--)
+ {
+ fakeFrame = {
+ parent: fakeFrame,
+ location: {
+ href: message.frames[i].location
+ },
+ document: {
+ documentElement: {}
+ },
+ QueryInterface: function() {return this;},
+ getInterface: function() {return this;},
+ usePrivateBrowsing: (fakeFrame ? fakeFrame.usePrivateBrowsing : message.frames[i].privateBrowsing)
+ };
+ fakeFrame.top = fakeFrame.parent || fakeFrame;
+ if (!fakeFrame.parent)
+ fakeFrame.parent = fakeFrame;
+
+ let sitekey = message.frames[i].sitekey || null;
+ fakeFrame.document.documentElement.getAttribute = function(attr)
+ {
+ if (attr == "data-adblockkey")
+ return sitekey;
+ else
+ return null;
+ };
+ }
+
+ let {Policy} = require("contentPolicy");
+ return !Policy.processNode(fakeFrame, fakeFrame.document, Policy.type.ELEMHIDE, filter);
+ },
+
+ /**
* Will be set to true if apply() is running (reentrance protection).
* @type Boolean
*/
_applying: false,
/**
* Will be set to true if an apply() call arrives while apply() is already
* running (delayed execution).
@@ -308,17 +362,17 @@ let ElemHide = exports.ElemHide =
throw Cr.NS_ERROR_NOT_AVAILABLE;
function escapeChar(match)
{
return "\\" + match.charCodeAt(0).toString(16) + " ";
}
// Return CSS data
- let cssTemplate = "-moz-binding: url(about:" + AboutHandler.aboutPrefix + "?%ID%#dummy) !important;";
+ let cssTemplate = "-moz-binding: url(about:abp-elemhidehit?%ID%#dummy) !important;";
for (let domain in domains)
{
let rules = [];
let list = domains[domain];
if (domain)
yield ('@-moz-document domain("' + domain.split(",").join('"),domain("') + '"){').replace(/[^\x01-\x7F]/g, escapeChar);
else
Index: lib/elemHideHitRegistration.js
===================================================================
--- a/lib/elemHideHitRegistration.js
+++ b/lib/elemHideHitRegistration.js
@@ -14,25 +14,70 @@
* You should have received a copy of the GNU General Public License
* along with Adblock Plus. If not, see .
*/
/**
* @fileOverview Hit counts for element hiding.
*/
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+try
+{
+ // Hack: SDK loader masks our Components object with a getter.
+ let proto = Object.getPrototypeOf(this);
+ let property = Object.getOwnPropertyDescriptor(proto, "Components");
+ if (property && property.get)
+ delete proto.Components;
+}
+catch (e)
+{
+ Cu.reportError(e);
+}
+
+let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
+let {PrivateBrowsingUtils} = Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm")
let {Utils} = require("utils");
+let messageID = 0;
+
+// The allowXBL binding below won't have any effect on the element. For elements
+// that should be hidden however we don't return any binding at all, this makes
+// Gecko stop constructing the node - it cannot be shown.
+const allowXBL = "";
+const hideXBL = "";
+
+function getFrames(window)
+{
+ let frames = [];
+ while (window)
+ {
+ let frame = {
+ location: window.location.href,
+ sitekey: null
+ };
+
+ let documentElement = window.document && window.document.documentElement;
+ if (documentElement)
+ frame.sitekey = documentElement.getAttribute("data-adblockkey")
+
+ if (window == window.parent)
+ frame.privateBrowsing = PrivateBrowsingUtils.isWindowPrivate(window);
+
+ frames.push(frame);
+ window = (window != window.parent ? window.parent : null);
+ }
+ return frames;
+}
+
/**
* about: URL module used to count hits.
* @class
*/
-let AboutHandler = exports.AboutHandler =
+let AboutHandler =
{
classID: Components.ID("{55fb7be0-1dd2-11b2-98e6-9e97caf8ba67}"),
classDescription: "Element hiding hit registration protocol handler",
aboutPrefix: "abp-elemhidehit",
/**
* Registers handler on startup.
*/
@@ -103,58 +148,55 @@ HitRegistrationChannel.prototype = {
notificationCallbacks: null,
loadFlags: 0,
loadGroup: null,
name: null,
status: Cr.NS_OK,
asyncOpen: function(listener, context)
{
- let stream = this.open();
- Utils.runAsync(() =>
+ let responseMessage = "AdblockPlus:ElemHideHit:Response" + (++messageID);
+
+ let processResponse = (message) =>
{
+ removeMessageListener(responseMessage, processResponse);
+
+ let data = (message.data ? hideXBL : allowXBL);
+ let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
+ stream.setData(data, data.length);
+
try {
listener.onStartRequest(this, context);
} catch(e) {}
try {
listener.onDataAvailable(this, context, stream, 0, stream.available());
} catch(e) {}
try {
listener.onStopRequest(this, context, Cr.NS_OK);
} catch(e) {}
+ };
+
+ addMessageListener(responseMessage, processResponse);
+ sendAsyncMessage("AdblockPlus:ElemHideHit", {
+ responseMessage,
+ key: this.key,
+ frames: getFrames(Utils.getRequestWindow(this))
});
},
asyncOpen2: function(listener)
{
if (!this.loadInfo.triggeringPrincipal.equals(Utils.systemPrincipal))
throw Cr.NS_ERROR_FAILURE;
this.asyncOpen(listener, null);
},
open: function()
{
- let {Policy} = require("contentPolicy");
- let {ElemHide} = require("elemHide");
-
- // This dummy binding below won't have any effect on the element. For
- // elements that should be hidden however we don't return any binding at
- // all, this makes Gecko stop constructing the node - it cannot be shown.
- let data = "";
- let filter = ElemHide.getFilterByKey(this.key);
- if (filter)
- {
- let wnd = Utils.getRequestWindow(this);
- if (wnd && wnd.document && !Policy.processNode(wnd, wnd.document, Policy.type.ELEMHIDE, filter))
- data = "";
- }
-
- let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
- stream.setData(data, data.length);
- return stream;
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
isPending: function()
{
return false;
},
cancel: function()
{
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
Index: lib/main.js
===================================================================
--- a/lib/main.js
+++ b/lib/main.js
@@ -17,25 +17,63 @@
/**
* @fileOverview Starts up Adblock Plus
*/
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
+bootstrapChildProcesses();
registerPublicAPI();
require("filterListener");
require("contentPolicy");
require("synchronizer");
require("notification");
require("sync");
require("messageResponder");
require("ui");
+function bootstrapChildProcesses()
+{
+ let info = require("info");
+
+ // Huge hack: we cannot opt out of individual compatibility shims (see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1167802). So the about
+ // protocol shim will override our handler in the content process. Prevent
+ // this by making sure it isn't messaged.
+ try
+ {
+ let {AboutProtocolParent} = Cu.import("resource://gre/modules/RemoteAddonsParent.jsm", {});
+ if (AboutProtocolParent && typeof AboutProtocolParent.registerFactory == "function")
+ {
+ let origRegisterFactory = AboutProtocolParent.registerFactory;
+ AboutProtocolParent.registerFactory = function(addon, ...args)
+ {
+ if (addon != info.addonID)
+ origRegisterFactory.call(this, addon, ...args);
+ }
+ onShutdown.add(() => AboutProtocolParent.registerFactory = origRegisterFactory);
+ }
+ }
+ catch(e) {}
+
+ let processScript = info.addonRoot + "lib/child/bootstrap.js?" + Math.random();
+ let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+ .getService(Ci.nsIProcessScriptLoader)
+ .QueryInterface(Ci.nsIMessageBroadcaster);
+ messageManager.loadProcessScript(processScript, true);
+ messageManager.broadcastAsyncMessage("AdblockPlus:Info", info);
+
+ onShutdown.add(() => {
+ messageManager.broadcastAsyncMessage("AdblockPlus:Shutdown", processScript);
+ messageManager.removeDelayedProcessScript(processScript);
+ });
+}
+
function registerPublicAPI()
{
let {addonRoot} = require("info");
let uri = Services.io.newURI(addonRoot + "lib/Public.jsm", null, null);
if (uri instanceof Ci.nsIMutable)
uri.mutable = false;
Index: lib/utils.js
===================================================================
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -599,17 +599,17 @@ XPCOMUtils.defineLazyServiceGetter(Utils
XPCOMUtils.defineLazyServiceGetter(Utils, "dateFormatter", "@mozilla.org/intl/scriptabledateformat;1", "nsIScriptableDateFormat");
XPCOMUtils.defineLazyServiceGetter(Utils, "httpProtocol", "@mozilla.org/network/protocol;1?name=http", "nsIHttpProtocolHandler");
XPCOMUtils.defineLazyServiceGetter(Utils, "clipboard", "@mozilla.org/widget/clipboard;1", "nsIClipboard");
XPCOMUtils.defineLazyServiceGetter(Utils, "clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
XPCOMUtils.defineLazyGetter(Utils, "crypto", function()
{
try
{
- let ctypes = Components.utils.import("resource://gre/modules/ctypes.jsm", null).ctypes;
+ let ctypes = Cu.import("resource://gre/modules/ctypes.jsm", null).ctypes;
let nsslib;
try
{
nsslib = ctypes.open(ctypes.libraryName("nss3"));
}
catch (e)
{
Index: metadata.gecko
===================================================================
--- a/metadata.gecko
+++ b/metadata.gecko
@@ -24,21 +24,21 @@ es=http://adblockplus.org/es/
fr=http://adblockplus.org/fr/
he=http://adblockplus.org/he/
ko=http://adblockplus.org/ko/
ru=http://adblockplus.org/ru/
zh-CN=https://adblockplus.org/zh_CN/
zh-TW=https://adblockplus.org/zh_TW/
[compat]
-firefox=29.0/45.0
-fennec2=29.0/45.0
-thunderbird=29.0/45.0
-seamonkey=2.26/2.41
-toolkit=29.0/45.0
+firefox=38.0/45.0
+fennec2=38.0/45.0
+thunderbird=38.0/45.0
+seamonkey=2.35/2.41
+toolkit=38.0/45.0
adblockbrowser=1.0/1.0
[mapping]
chrome/content/ui/firstRun.html = adblockplusui/firstRun.html
chrome/content/ui/firstRun.js = adblockplusui/firstRun.js
chrome/content/ui/i18n.js = adblockplusui/i18n.js
chrome/content/ui/skin/firstRun.css = adblockplusui/skin/firstRun.css
chrome/content/ui/skin/abp-128.png = adblockplusui/skin/abp-128.png