Index: lib/child/contentPolicy.js |
=================================================================== |
--- a/lib/child/contentPolicy.js |
+++ b/lib/child/contentPolicy.js |
@@ -50,62 +50,95 @@ let collapsedClass = null; |
/** |
* Maps numerical content type IDs to strings. |
* @type Map.<number,string> |
*/ |
let types = new Map(); |
/** |
- * Checks whether a request should be allowed, hides it if necessary |
- * @param wnd {nsIDOMWindow} |
- * @param node {nsIDOMElement} |
- * @param contentType {String} |
- * @param location {String} |
+ * Processes parent's response to the ShouldAllow message. |
+ * @param {nsIDOMWindow} window window that the request is associated with |
+ * @param {nsIDOMElement} node DOM element that the request is associated with |
+ * @param {Object|undefined} response object received as response |
* @return {Boolean} false if the request should be blocked |
*/ |
-function shouldAllow(window, node, contentType, location) |
+function processPolicyResponse(window, node, response) |
{ |
- let response = sendSyncMessage("AdblockPlus:ShouldAllow", { |
- contentType: contentType, |
- location: location, |
- frames: getFrames(window), |
- isPrivate: isPrivate(window) |
- }); |
if (typeof response == "undefined") |
return true; |
let {allow, collapse, hits} = response; |
+ let isObject = false; |
for (let {frameIndex, contentType, docDomain, thirdParty, location, filter} of hits) |
{ |
+ if (contentType == "OBJECT") |
+ isObject = true; |
+ |
let context = node; |
if (typeof frameIndex == "number") |
{ |
context = window; |
for (let i = 0; i < frameIndex; i++) |
context = context.parent; |
context = context.document; |
} |
RequestNotifier.addNodeData(context, window.top, contentType, docDomain, thirdParty, location, filter); |
} |
if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) |
{ |
// Track mouse events for objects |
- if (allow && contentType == "OBJECT") |
+ if (allow && isObject) |
{ |
node.addEventListener("mouseover", objectMouseEventHander, true); |
node.addEventListener("mouseout", objectMouseEventHander, true); |
} |
if (collapse) |
schedulePostProcess(node); |
} |
+ return allow; |
+} |
- return allow; |
+/** |
+ * Checks whether a request should be allowed, hides it if necessary |
+ * @param {nsIDOMWindow} window |
+ * @param {nsIDOMElement} node |
+ * @param {String} contentType |
+ * @param {String} location |
+ * @return {Boolean} false if the request should be blocked |
+ */ |
+function shouldAllow(window, node, contentType, location) |
+{ |
+ return processPolicyResponse(window, node, sendSyncMessage("AdblockPlus:ShouldAllow", { |
+ contentType, |
+ location, |
+ frames: getFrames(window), |
+ isPrivate: isPrivate(window) |
+ })); |
+} |
+ |
+/** |
+ * Asynchronously checks whether a request should be allowed. |
+ * @param {nsIDOMWindow} window |
+ * @param {nsIDOMElement} node |
+ * @param {String} contentType |
+ * @param {String} location |
+ * @param {Function} callback callback to be called with a boolean value, if |
+ * false the request should be blocked |
+ */ |
+function shouldAllowAsync(window, node, contentType, location, callback) |
+{ |
+ sendAsyncMessage("AdblockPlus:ShouldAllow", { |
+ contentType, |
+ location, |
+ frames: getFrames(window), |
+ isPrivate: isPrivate(window) |
+ }, response => callback(processPolicyResponse(window, node, response))); |
} |
/** |
* Actual nsIContentPolicy and nsIChannelEventSink implementation |
* @class |
*/ |
var PolicyImplementation = |
{ |
@@ -229,17 +262,17 @@ var PolicyImplementation = |
}, |
// |
// nsIChannelEventSink interface implementation |
// |
asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) |
{ |
- let result = Cr.NS_OK; |
+ let async = false; |
try |
{ |
// nsILoadInfo.contentPolicyType was introduced in Gecko 35, then |
// renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. |
let loadInfo = oldChannel.loadInfo; |
let contentType = ("externalContentPolicyType" in loadInfo ? |
loadInfo.externalContentPolicyType : loadInfo.contentPolicyType); |
if (!contentType) |
@@ -258,27 +291,31 @@ var PolicyImplementation = |
// seen the original channel yet because the redirect happened before |
// the async code in observe() had a chance to run. |
this.observe(wnd, "content-document-global-created", null, oldChannel.URI.spec); |
this.observe(wnd, "content-document-global-created", null, newChannel.URI.spec); |
} |
return; |
} |
- if (!shouldAllow(wnd, wnd.document, types.get(contentType), newChannel.URI.spec)) |
- result = Cr.NS_BINDING_ABORTED; |
+ shouldAllowAsync(wnd, wnd.document, types.get(contentType), newChannel.URI.spec, function(allow) |
+ { |
+ callback.onRedirectVerifyCallback(allow ? Cr.NS_OK : Cr.NS_BINDING_ABORTED); |
+ }); |
+ async = true; |
} |
catch (e) |
{ |
// We shouldn't throw exceptions here - this will prevent the redirect. |
Cu.reportError(e); |
} |
finally |
{ |
- callback.onRedirectVerifyCallback(result); |
+ if (!async) |
+ callback.onRedirectVerifyCallback(Cr.NS_OK); |
} |
}, |
// |
// nsIFactory interface implementation |
// |
createInstance: function(outer, iid) |