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

Side by Side Diff: lib/child/elemHide.js

Issue 29356078: Issue 524 - Stop using @-moz-document (Closed) Base URL: https://hg.adblockplus.org/adblockplus
Patch Set: Created Oct. 6, 2016, 11:17 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « dependencies ('k') | lib/contentPolicy.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 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 Hit counts for element hiding. 19 * @fileOverview Serves CSS for element hiding and processes hits.
20 */ 20 */
21 21
22 try 22 try
23 { 23 {
24 // Hack: SDK loader masks our Components object with a getter. 24 // Hack: SDK loader masks our Components object with a getter.
25 let proto = Object.getPrototypeOf(this); 25 let proto = Object.getPrototypeOf(this);
26 let property = Object.getOwnPropertyDescriptor(proto, "Components"); 26 let property = Object.getOwnPropertyDescriptor(proto, "Components");
27 if (property && property.get) 27 if (property && property.get)
28 delete proto.Components; 28 delete proto.Components;
29 } 29 }
30 catch (e) 30 catch (e)
31 { 31 {
32 Cu.reportError(e); 32 Cu.reportError(e);
33 } 33 }
34 34
35 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); 35 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
36 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); 36 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
37 37
38 let {shouldAllowAsync} = require("child/contentPolicy"); 38 let {shouldAllowAsync} = require("child/contentPolicy");
39 let {getFrames, isPrivate} = require("child/utils"); 39 let {getFrames, isPrivate} = require("child/utils");
40 let {RequestNotifier} = require("child/requestNotifier"); 40 let {RequestNotifier} = require("child/requestNotifier");
41 let {port} = require("messaging"); 41 let {port} = require("messaging");
42 let {Utils} = require("utils"); 42 let {Utils} = require("utils");
43 43
44 // The allowXBL binding below won't have any effect on the element. For elements
45 // that should be hidden however we don't return any binding at all, this makes
46 // Gecko stop constructing the node - it cannot be shown.
47 const allowXBL = "<bindings xmlns='http://www.mozilla.org/xbl'><binding id='dumm y' bindToUntrustedContent='true'/></bindings>";
48 const hideXBL = "<bindings xmlns='http://www.mozilla.org/xbl'/>";
49
50 const notImplemented = () => Cr.NS_ERROR_NOT_IMPLEMENTED; 44 const notImplemented = () => Cr.NS_ERROR_NOT_IMPLEMENTED;
51 45
52 /** 46 /**
53 * about: URL module used to count hits. 47 * about: URL module used to count hits.
54 * @class 48 * @class
55 */ 49 */
56 let AboutHandler = 50 let AboutHandler =
57 { 51 {
58 classID: Components.ID("{55fb7be0-1dd2-11b2-98e6-9e97caf8ba67}"), 52 classID: Components.ID("{55fb7be0-1dd2-11b2-98e6-9e97caf8ba67}"),
59 classDescription: "Element hiding hit registration protocol handler", 53 classDescription: "Element hiding hit registration protocol handler",
(...skipping 29 matching lines...) Expand all
89 // About module implementation 83 // About module implementation
90 // 84 //
91 85
92 getURIFlags: function(uri) 86 getURIFlags: function(uri)
93 { 87 {
94 return Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT; 88 return Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
95 }, 89 },
96 90
97 newChannel: function(uri, loadInfo) 91 newChannel: function(uri, loadInfo)
98 { 92 {
99 let match = /\?(?:hit(\d+)|css)$/.exec(uri.path); 93 let match = /\?hit(\d+)$/.exec(uri.path);
100 if (!match) 94 if (match)
101 throw Cr.NS_ERROR_FAILURE; 95 return new HitRegistrationChannel(uri, loadInfo, match[1]);
102 96
103 if (match[1]) 97 match = /\?css(?:=(.*?))?$/.exec(uri.path);
104 return new HitRegistrationChannel(uri, loadInfo, match[1]); 98 if (match)
105 else 99 {
106 return new StyleDataChannel(uri, loadInfo); 100 return new StyleDataChannel(uri, loadInfo,
101 match[1] ? decodeURIComponent(match[1]) : null);
102 }
103
104 throw Cr.NS_ERROR_FAILURE;
107 }, 105 },
108 106
109 QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory, Ci.nsIAboutModule]) 107 QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory, Ci.nsIAboutModule])
110 }; 108 };
111 AboutHandler.init(); 109 AboutHandler.init();
112 110
113 /** 111 /**
114 * Base class for channel implementations, subclasses usually only need to 112 * Base class for channel implementations, subclasses usually only need to
115 * override BaseChannel._getResponse() method. 113 * override BaseChannel._getResponse() method.
116 * @constructor 114 * @constructor
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 203
206 isPending: () => false, 204 isPending: () => false,
207 cancel: notImplemented, 205 cancel: notImplemented,
208 suspend: notImplemented, 206 suspend: notImplemented,
209 resume: notImplemented, 207 resume: notImplemented,
210 208
211 QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest]) 209 QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
212 }; 210 };
213 211
214 /** 212 /**
215 * Channel returning CSS data for the global stylesheet. 213 * Channel returning CSS data for the global stylesheet.
kzar 2016/10/06 12:10:46 Nit: I guess this comment should be updated now it
Wladimir Palant 2016/10/06 12:27:28 Done.
216 * @constructor 214 * @constructor
217 */ 215 */
218 function StyleDataChannel(uri, loadInfo) 216 function StyleDataChannel(uri, loadInfo, domain)
219 { 217 {
220 BaseChannel.call(this, uri, loadInfo); 218 BaseChannel.call(this, uri, loadInfo);
219 this._domain = domain;
221 } 220 }
222 StyleDataChannel.prototype = { 221 StyleDataChannel.prototype = {
223 __proto__: BaseChannel.prototype, 222 __proto__: BaseChannel.prototype,
224 contentType: "text/css", 223 contentType: "text/css",
224 _domain: null,
225 225
226 _getResponse: function() 226 _getResponse: function()
227 { 227 {
228 function escapeChar(match) 228 function escapeChar(match)
229 { 229 {
230 return "\\" + match.charCodeAt(0).toString(16) + " "; 230 return "\\" + match.charCodeAt(0).toString(16) + " ";
231 } 231 }
232 232
233 // Would be great to avoid sync messaging here but nsIStyleSheetService 233 // Would be great to avoid sync messaging here but nsIStyleSheetService
234 // insists on opening channels synchronously. 234 // insists on opening channels synchronously.
235 let domains = port.emitSync("getSelectors"); 235 let [selectors, keys] = (this._domain ?
236 port.emitSync("getSelectorsForDomain", this._domain) :
kzar 2016/10/06 12:10:46 Dumb question but how does getSelectorsForDomain a
Wladimir Palant 2016/10/06 12:27:28 This is the content process - we cannot require El
kzar 2016/10/06 13:02:32 Ah I see.
237 port.emitSync("getUnconditionalSelectors"));
236 238
237 let cssPrefix = "{-moz-binding: url(about:abp-elemhide?hit"; 239 let cssPrefix = "{-moz-binding: url(about:abp-elemhide?hit";
238 let cssSuffix = "#dummy) !important;}\n"; 240 let cssSuffix = "#dummy) !important;}\n";
239 let result = []; 241 let result = [];
240 242
241 for (let [domain, selectors] of domains) 243 for (let i = 0; i < selectors.length; i++)
242 { 244 {
243 if (domain) 245 let selector = selectors[i];
244 { 246 let key = keys[i];
245 result.push('@-moz-document domain("', 247 result.push(selector.replace(/[^\x01-\x7F]/g, escapeChar),
246 domain.replace(/[^\x01-\x7F]/g, escapeChar) 248 cssPrefix, key, cssSuffix);
247 .split(",").join('"),domain("'),
248 '"){\n');
249 }
250 else
251 {
252 // Only allow unqualified rules on a few protocols to prevent them
253 // from blocking chrome content
254 result.push('@-moz-document url-prefix("http://"),',
255 'url-prefix("https://"),url-prefix("mailbox://"),',
256 'url-prefix("imap://"),url-prefix("news://"),',
257 'url-prefix("snews://"){\n');
258 }
259
260 for (let [selector, key] of selectors)
261 {
262 result.push(selector.replace(/[^\x01-\x7F]/g, escapeChar),
263 cssPrefix, key, cssSuffix);
264 }
265
266 result.push("}\n");
267 } 249 }
268 250
269 return result.join(""); 251 return result.join("");
270 } 252 }
271 }; 253 };
272 254
273 /** 255 /**
274 * Channel returning data for element hiding hits. 256 * Channel returning data for element hiding hits.
275 * @constructor 257 * @constructor
276 */ 258 */
277 function HitRegistrationChannel(uri, loadInfo, key) 259 function HitRegistrationChannel(uri, loadInfo, key)
278 { 260 {
279 BaseChannel.call(this, uri, loadInfo); 261 BaseChannel.call(this, uri, loadInfo);
280 this.key = key; 262 this.key = key;
281 } 263 }
282 HitRegistrationChannel.prototype = { 264 HitRegistrationChannel.prototype = {
283 __proto__: BaseChannel.prototype, 265 __proto__: BaseChannel.prototype,
284 key: null, 266 key: null,
285 contentType: "text/xml", 267 contentType: "text/xml",
286 268
287 _getResponse: function() 269 _getResponse: function()
288 { 270 {
289 return new Promise((resolve, reject) => 271 let window = Utils.getRequestWindow(this);
272 port.emitWithResponse("registerElemHideHit", {
273 key: this.key,
274 frames: getFrames(window),
275 isPrivate: isPrivate(window)
276 }).then(hit =>
290 { 277 {
291 let window = Utils.getRequestWindow(this); 278 if (hit)
292 shouldAllowAsync(window, window.document, "ELEMHIDE", this.key, allow => 279 RequestNotifier.addNodeData(window.document, window.top, hit);
293 {
294 resolve(allow ? allowXBL : hideXBL);
295 });
296 }); 280 });
281 return "<bindings xmlns='http://www.mozilla.org/xbl'/>";
297 } 282 }
298 }; 283 };
299 284
300 let observer = { 285 let observer = {
301 QueryInterface: XPCOMUtils.generateQI([ 286 QueryInterface: XPCOMUtils.generateQI([
302 Ci.nsIObserver, Ci.nsISupportsWeakReference 287 Ci.nsIObserver, Ci.nsISupportsWeakReference
303 ]), 288 ]),
304 289
305 topic: "document-element-inserted", 290 topic: "document-element-inserted",
306 styleURL: Utils.makeURI("about:abp-elemhide?css"), 291 styleURL: Utils.makeURI("about:abp-elemhide?css"),
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 utils.addSheet(this.sheet, Ci.nsIStyleSheetService.USER_SHEET); 353 utils.addSheet(this.sheet, Ci.nsIStyleSheetService.USER_SHEET);
369 } 354 }
370 catch (e) 355 catch (e)
371 { 356 {
372 // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add 357 // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add
373 // the stylesheet multiple times to the same document (the observer 358 // the stylesheet multiple times to the same document (the observer
374 // will be notified twice for some documents). 359 // will be notified twice for some documents).
375 if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE) 360 if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE)
376 throw e; 361 throw e;
377 } 362 }
363
364 let host = subject.location.hostname;
365 if (host)
366 {
367 try
368 {
369 utils.loadSheetUsingURIString(this.styleURL.spec + "=" +
370 encodeURIComponent(host), Ci.nsIStyleSheetService.USER_SHEET);
371 }
372 catch (e)
373 {
374 // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to ad d
375 // the stylesheet multiple times to the same document (the observer
376 // will be notified twice for some documents).
377 if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE)
378 throw e;
379 }
380 }
378 } 381 }
379 else if (filter) 382 else if (filter)
380 { 383 {
381 RequestNotifier.addNodeData(window.document, window.top, { 384 RequestNotifier.addNodeData(window.document, window.top, {
382 contentType, docDomain, thirdParty, location, filter, filterType 385 contentType, docDomain, thirdParty, location, filter, filterType
383 }); 386 });
384 } 387 }
385 }); 388 });
386 } 389 }
387 }; 390 };
388 observer.init(); 391 observer.init();
OLDNEW
« no previous file with comments | « dependencies ('k') | lib/contentPolicy.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld