Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: lib/contentPolicy.js

Issue 29329404: Issue 443 - Fix blocking pop-ups after redirect (Closed)
Left Patch Set: Made sure to look at the original channel as well Created Oct. 27, 2015, 1:29 p.m.
Right Patch Set: Improved comment Created Nov. 5, 2015, 3:51 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 /** 18 /**
19 * @fileOverview Content policy implementation, responsible for blocking things. 19 * @fileOverview Content policy implementation, responsible for blocking things.
20 */ 20 */
21 21
22 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 22 "use strict";
23 Cu.import("resource://gre/modules/Services.jsm"); 23
24 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
25 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
24 26
25 let {Utils} = require("utils"); 27 let {Utils} = require("utils");
26 let {Prefs} = require("prefs"); 28 let {Prefs} = require("prefs");
27 let {FilterStorage} = require("filterStorage"); 29 let {FilterStorage} = require("filterStorage");
28 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); 30 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses");
29 let {defaultMatcher} = require("matcher"); 31 let {defaultMatcher} = require("matcher");
30 let {objectMouseEventHander} = require("objectTabs"); 32 let {objectMouseEventHander} = require("objectTabs");
31 let {RequestNotifier} = require("requestNotifier"); 33 let {RequestNotifier} = require("requestNotifier");
32 let {ElemHide} = require("elemHide"); 34 let {ElemHide} = require("elemHide");
33 35
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 localizedDescr: {}, 81 localizedDescr: {},
80 82
81 /** 83 /**
82 * Lists the non-visual content types. 84 * Lists the non-visual content types.
83 * @type Object 85 * @type Object
84 */ 86 */
85 nonVisual: {}, 87 nonVisual: {},
86 88
87 /** 89 /**
88 * Map containing all schemes that should be ignored by content policy. 90 * Map containing all schemes that should be ignored by content policy.
89 * @type Object 91 * @type Set
90 */ 92 */
91 whitelistSchemes: {}, 93 whitelistSchemes: new Set(),
92 94
93 /** 95 /**
94 * Called on module startup, initializes various exported properties. 96 * Called on module startup, initializes various exported properties.
95 */ 97 */
96 init: function() 98 init: function()
97 { 99 {
98 // type constant by type description and type description by type constant 100 // type constant by type description and type description by type constant
99 let iface = Ci.nsIContentPolicy; 101 let iface = Ci.nsIContentPolicy;
100 for (let typeName of contentTypes) 102 for (let typeName of contentTypes)
101 { 103 {
(...skipping 25 matching lines...) Expand all
127 this.type.POPUP = 0xFFFE; 129 this.type.POPUP = 0xFFFE;
128 this.typeDescr[0xFFFE] = "POPUP"; 130 this.typeDescr[0xFFFE] = "POPUP";
129 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup"); 131 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup");
130 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP; 132 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP;
131 133
132 for (let type of nonVisualTypes) 134 for (let type of nonVisualTypes)
133 this.nonVisual[this.type[type]] = true; 135 this.nonVisual[this.type[type]] = true;
134 136
135 // whitelisted URL schemes 137 // whitelisted URL schemes
136 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) 138 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" "))
137 this.whitelistSchemes[scheme] = true; 139 this.whitelistSchemes.add(scheme);
138 140
139 // Generate class identifier used to collapse node and register correspondin g 141 // Generate class identifier used to collapse node and register correspondin g
140 // stylesheet. 142 // stylesheet.
141 let offset = "a".charCodeAt(0); 143 let offset = "a".charCodeAt(0);
142 for (let i = 0; i < 20; i++) 144 for (let i = 0; i < 20; i++)
143 collapsedClass += String.fromCharCode(offset + Math.random() * 26); 145 collapsedClass += String.fromCharCode(offset + Math.random() * 26);
144 146
145 let collapseStyle = Services.io.newURI("data:text/css," + 147 let collapseStyle = Services.io.newURI("data:text/css," +
146 encodeURIComponent("." + collapsedClass + 148 encodeURIComponent("." + collapsedClass +
147 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); 149 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null);
148 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); 150 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET);
149 onShutdown.add(function() 151 onShutdown.add(() =>
150 { 152 {
151 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); 153 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET);
152 }); 154 });
153 }, 155 },
154 156
155 /** 157 /**
156 * Checks whether a node should be blocked, hides it if necessary 158 * Checks whether a node should be blocked, hides it if necessary
157 * @param wnd {nsIDOMWindow} 159 * @param wnd {nsIDOMWindow}
158 * @param node {nsIDOMElement} 160 * @param node {nsIDOMElement}
159 * @param contentType {String} 161 * @param contentType {String}
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 return !match || match instanceof WhitelistFilter; 300 return !match || match instanceof WhitelistFilter;
299 }, 301 },
300 302
301 /** 303 /**
302 * Checks whether the location's scheme is blockable. 304 * Checks whether the location's scheme is blockable.
303 * @param location {nsIURI} 305 * @param location {nsIURI}
304 * @return {Boolean} 306 * @return {Boolean}
305 */ 307 */
306 isBlockableScheme: function(location) 308 isBlockableScheme: function(location)
307 { 309 {
308 return !(location.scheme in Policy.whitelistSchemes); 310 return !this.whitelistSchemes.has(location.scheme);
309 }, 311 },
310 312
311 /** 313 /**
312 * Checks whether a page is whitelisted. 314 * Checks whether a page is whitelisted.
313 * @param {String} url 315 * @param {String} url
314 * @param {String} [parentUrl] location of the parent page 316 * @param {String} [parentUrl] location of the parent page
315 * @param {String} [sitekey] public key provided on the page 317 * @param {String} [sitekey] public key provided on the page
316 * @return {Filter} filter that matched the URL or null if not whitelisted 318 * @return {Filter} filter that matched the URL or null if not whitelisted
317 */ 319 */
318 isWhitelisted: function(url, parentUrl, sitekey) 320 isWhitelisted: function(url, parentUrl, sitekey)
319 { 321 {
320 if (!url) 322 if (!url)
321 return null; 323 return null;
322 324
323 // Do not apply exception rules to schemes on our whitelistschemes list. 325 // Do not apply exception rules to schemes on our whitelistschemes list.
324 let match = /^([\w\-]+):/.exec(url); 326 let match = /^([\w\-]+):/.exec(url);
325 if (match && match[1] in Policy.whitelistSchemes) 327 if (match && this.whitelistSchemes.has(match[1]))
326 return null; 328 return null;
327 329
328 if (!parentUrl) 330 if (!parentUrl)
329 parentUrl = url; 331 parentUrl = url;
330 332
331 // Ignore fragment identifier 333 // Ignore fragment identifier
332 let index = url.indexOf("#"); 334 let index = url.indexOf("#");
333 if (index >= 0) 335 if (index >= 0)
334 url = url.substring(0, index); 336 url = url.substring(0, index);
335 337
336 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); 338 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey);
337 return (result instanceof WhitelistFilter ? result : null); 339 return (result instanceof WhitelistFilter ? result : null);
338 }, 340 },
339 341
340 /** 342 /**
341 * Checks whether the page loaded in a window is whitelisted for indication in the UI. 343 * Checks whether the page loaded in a window is whitelisted for indication in the UI.
342 * @param wnd {nsIDOMWindow} 344 * @param wnd {nsIDOMWindow}
343 * @return {Filter} matching exception rule or null if not whitelisted 345 * @return {Filter} matching exception rule or null if not whitelisted
344 */ 346 */
345 isWindowWhitelisted: function(wnd) 347 isWindowWhitelisted: function(wnd)
346 { 348 {
347 return Policy.isWhitelisted(getWindowLocation(wnd)); 349 return this.isWhitelisted(getWindowLocation(wnd));
348 }, 350 },
349 351
350 /** 352 /**
351 * Asynchronously re-checks filters for given nodes. 353 * Asynchronously re-checks filters for given nodes.
352 * @param {Node[]} nodes 354 * @param {Node[]} nodes
353 * @param {RequestEntry} entry 355 * @param {RequestEntry} entry
354 */ 356 */
355 refilterNodes: function(nodes, entry) 357 refilterNodes: function(nodes, entry)
356 { 358 {
357 // Ignore nodes that have been blocked already 359 // Ignore nodes that have been blocked already
(...skipping 24 matching lines...) Expand all
382 { 384 {
383 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); 385 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
384 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this); 386 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this);
385 387
386 let catMan = Utils.categoryManager; 388 let catMan = Utils.categoryManager;
387 for (let category of this.xpcom_categories) 389 for (let category of this.xpcom_categories)
388 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true); 390 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true);
389 391
390 Services.obs.addObserver(this, "content-document-global-created", true); 392 Services.obs.addObserver(this, "content-document-global-created", true);
391 393
392 onShutdown.add(function() 394 onShutdown.add(() =>
393 { 395 {
394 Services.obs.removeObserver(this, "content-document-global-created"); 396 Services.obs.removeObserver(this, "content-document-global-created");
395 397
396 for (let category of this.xpcom_categories) 398 for (let category of this.xpcom_categories)
397 catMan.deleteCategoryEntry(category, this.contractID, false); 399 catMan.deleteCategoryEntry(category, this.contractID, false);
398 400
399 registrar.unregisterFactory(this.classID, this); 401 registrar.unregisterFactory(this.classID, this);
400 }.bind(this)); 402 });
401 }, 403 },
402 404
403 // 405 //
404 // nsISupports interface implementation 406 // nsISupports interface implementation
405 // 407 //
406 408
407 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, 409 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver,
408 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), 410 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]),
409 411
410 // 412 //
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 let uri = additional || Utils.makeURI(subject.location.href); 460 let uri = additional || Utils.makeURI(subject.location.href);
459 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false)) 461 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false))
460 { 462 {
461 subject.stop(); 463 subject.stop();
462 Utils.runAsync(() => subject.close()); 464 Utils.runAsync(() => subject.close());
463 } 465 }
464 else if (uri.spec == "about:blank") 466 else if (uri.spec == "about:blank")
465 { 467 {
466 // An about:blank pop-up most likely means that a load will be 468 // An about:blank pop-up most likely means that a load will be
467 // initiated asynchronously. Wait for that. 469 // initiated asynchronously. Wait for that.
468 Utils.runAsync(function() 470 Utils.runAsync(() =>
469 { 471 {
470 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor) 472 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor)
471 .getInterface(Ci.nsIDocShell) 473 .getInterface(Ci.nsIDocShell)
472 .QueryInterface(Ci.nsIDocumentLoader) 474 .QueryInterface(Ci.nsIDocumentLoader)
473 .documentChannel; 475 .documentChannel;
474 if (channel) 476 if (channel)
475 this.observe(subject, topic, data, channel.URI); 477 this.observe(subject, topic, data, channel.URI);
476 }); 478 });
477 } 479 }
478 break; 480 break;
479 } 481 }
480 } 482 }
481 }, 483 },
482 484
483 // 485 //
484 // nsIChannelEventSink interface implementation 486 // nsIChannelEventSink interface implementation
485 // 487 //
486 488
487 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) 489 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback)
488 { 490 {
489 let result = Cr.NS_OK; 491 let result = Cr.NS_OK;
490 try 492 try
491 { 493 {
492 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then 494 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then
493 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. 495 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44.
494 let loadInfo = oldChannel.loadInfo; 496 let loadInfo = oldChannel.loadInfo;
495 let contentType = loadInfo.externalContentPolicyType || loadInfo.contentPo licyType; 497 let contentType = ("externalContentPolicyType" in loadInfo ?
498 loadInfo.externalContentPolicyType : loadInfo.contentPolicyType);
496 if (!contentType) 499 if (!contentType)
497 return; 500 return;
498 501
499 let wnd = Utils.getRequestWindow(newChannel); 502 let wnd = Utils.getRequestWindow(newChannel);
500 if (!wnd) 503 if (!wnd)
501 return; 504 return;
502 505
503 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) 506 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT)
504 { 507 {
505 if (wnd.history.length <= 1 && wnd.opener) 508 if (wnd.history.length <= 1 && wnd.opener)
506 { 509 {
507 // Special treatment for pop-up windows. Note that we might not have 510 // Special treatment for pop-up windows - this will close the window
511 // rather than preventing the redirect. Note that we might not have
508 // seen the original channel yet because the redirect happened before 512 // seen the original channel yet because the redirect happened before
509 // the async code in observe() had a chance to run. 513 // the async code in observe() had a chance to run.
510 this.observe(wnd, "content-document-global-created", null, oldChannel. URI); 514 this.observe(wnd, "content-document-global-created", null, oldChannel. URI);
511 this.observe(wnd, "content-document-global-created", null, newChannel. URI); 515 this.observe(wnd, "content-document-global-created", null, newChannel. URI);
512 } 516 }
tschuster 2015/11/05 15:27:18 I think your comment about this patch set would he
Wladimir Palant 2015/11/05 15:51:59 Done.
513 return; 517 return;
514 } 518 }
515 519
516 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse)) 520 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse))
517 result = Cr.NS_BINDING_ABORTED; 521 result = Cr.NS_BINDING_ABORTED;
518 } 522 }
519 catch (e) 523 catch (e)
520 { 524 {
521 // We shouldn't throw exceptions here - this will prevent the redirect. 525 // We shouldn't throw exceptions here - this will prevent the redirect.
522 Cu.reportError(e); 526 Cu.reportError(e);
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 if (!wnd || wnd.closed) 729 if (!wnd || wnd.closed)
726 return; 730 return;
727 731
728 if (entry.type == Policy.type.OBJECT) 732 if (entry.type == Policy.type.OBJECT)
729 { 733 {
730 node.removeEventListener("mouseover", objectMouseEventHander, true); 734 node.removeEventListener("mouseover", objectMouseEventHander, true);
731 node.removeEventListener("mouseout", objectMouseEventHander, true); 735 node.removeEventListener("mouseout", objectMouseEventHander, true);
732 } 736 }
733 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ; 737 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ;
734 } 738 }
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld