| 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) |