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

Delta Between Two Patch Sets: lib/contentPolicy.js

Issue 6337686776315904: Issue 394 - hit statistics tool data collection (Closed)
Left Patch Set: Addressed Wladimir comments (save data in the database instead of memory) Created Feb. 19, 2016, 5:20 p.m.
Right Patch Set: Use Downloader to send the data to server Created April 6, 2016, 3 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
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-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 Content policy implementation, responsible for blocking things. 19 * @fileOverview Content policy implementation, responsible for blocking things.
20 */ 20 */
21 21
22 "use strict"; 22 "use strict";
23 23
24 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); 24 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
25 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); 25 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
26 26
27 let {Utils} = require("utils"); 27 let {Utils} = require("utils");
28 let {port} = require("messaging");
28 let {Prefs} = require("prefs"); 29 let {Prefs} = require("prefs");
29 let {FilterStorage} = require("filterStorage"); 30 let {FilterStorage} = require("filterStorage");
30 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); 31 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses");
31 let {defaultMatcher} = require("matcher"); 32 let {defaultMatcher} = require("matcher");
32 let {ElemHide} = require("elemHide"); 33 let {ElemHide} = require("elemHide");
33 34
34 /** 35 /**
35 * Public policy checking functions and auxiliary objects 36 * Public policy checking functions and auxiliary objects
36 * @class 37 * @class
37 */ 38 */
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 81
81 /** 82 /**
82 * Called on module startup, initializes various exported properties. 83 * Called on module startup, initializes various exported properties.
83 */ 84 */
84 init: function() 85 init: function()
85 { 86 {
86 // whitelisted URL schemes 87 // whitelisted URL schemes
87 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) 88 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" "))
88 this.whitelistSchemes.add(scheme); 89 this.whitelistSchemes.add(scheme);
89 90
90 Utils.addChildMessageListener("AdblockPlus:ShouldAllow", message => this.sho uldAllow(message)); 91 port.on("shouldAllow", (message, sender) => this.shouldAllow(message));
91 92
92 // Generate class identifier used to collapse nodes and register 93 // Generate class identifier used to collapse nodes and register
93 // corresponding stylesheet. 94 // corresponding stylesheet.
94 let collapsedClass = ""; 95 let collapsedClass = "";
95 let offset = "a".charCodeAt(0); 96 let offset = "a".charCodeAt(0);
96 for (let i = 0; i < 20; i++) 97 for (let i = 0; i < 20; i++)
97 collapsedClass += String.fromCharCode(offset + Math.random() * 26); 98 collapsedClass += String.fromCharCode(offset + Math.random() * 26);
98 Utils.addChildMessageListener("AdblockPlus:GetCollapsedClass", () => collaps edClass); 99 port.on("getCollapsedClass", (message, sender) => collapsedClass);
99 100
100 let collapseStyle = Services.io.newURI("data:text/css," + 101 let collapseStyle = Services.io.newURI("data:text/css," +
101 encodeURIComponent("." + collapsedClass + 102 encodeURIComponent("." + collapsedClass +
102 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); 103 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null);
103 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); 104 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET);
104 onShutdown.add(() => 105 onShutdown.add(() =>
105 { 106 {
106 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); 107 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET);
107 }); 108 });
108 }, 109 },
109 110
110 /** 111 /**
111 * Checks whether a node should be blocked, hides it if necessary 112 * Checks whether a node should be blocked, hides it if necessary
112 * @param {Object} data request data 113 * @param {Object} data request data
113 * @param {String} data.contentType 114 * @param {String} data.contentType
114 * @param {String} data.location location of the request, filter key if conte ntType is ELEMHIDE 115 * @param {String} data.location location of the request, filter key if conte ntType is ELEMHIDE
115 * @param {Object[]} data.frames 116 * @param {Object[]} data.frames
116 * @param {Boolean} data.isPrivate true if the request belongs to a private b rowsing window 117 * @param {Boolean} data.isPrivate true if the request belongs to a private b rowsing window
117 * @return {Object} An object containing properties allow, collapse and hits 118 * @return {Object} An object containing properties allow, collapse and hits
118 * indicating how this request should be handled. 119 * indicating how this request should be handled.
119 */ 120 */
120 shouldAllow: function({contentType, location, frames, isPrivate}) 121 shouldAllow: function({contentType, location, frames, isPrivate})
121 { 122 {
122 let hits = []; 123 let hits = [];
123 124
124 function addHit(frameIndex, contentType, docDomain, thirdParty, location, fi lter) 125 function addHit(frameIndex, contentType, docDomain, thirdParty, location, fi lter)
125 { 126 {
126 if (filter && !isPrivate) 127 if (filter && !isPrivate)
127 FilterStorage.increaseHitCount(filter, docDomain); 128 FilterStorage.increaseHitCount(filter, docDomain, thirdParty);
128 129
129 hits.push({ 130 hits.push({
130 frameIndex, contentType, docDomain, thirdParty, location, 131 frameIndex, contentType, docDomain, thirdParty, location,
131 filter: filter ? filter.text : null, 132 filter: filter ? filter.text : null,
132 filterType: filter ? filter.type : null 133 filterType: filter ? filter.type : null
133 }); 134 });
134 } 135 }
135 136
136 function response(allow, collapse) 137 function response(allow, collapse)
137 { 138 {
138 return {allow, collapse, hits}; 139 return {allow, collapse, hits};
139 } 140 }
140 141
141 // Ignore whitelisted schemes 142 // Ignore whitelisted schemes
142 if (!this.isBlockableScheme(location)) 143 if (!this.isBlockableScheme(location))
143 return response(true, false); 144 return response(true, false);
144 145
145 // Interpret unknown types as "other" 146 // Interpret unknown types as "other"
146 contentType = this.contentTypes.get(contentType) || "OTHER"; 147 contentType = this.contentTypes.get(contentType) || "OTHER";
147 148
149 let nogeneric = false;
150 if (Prefs.enabled)
151 {
152 let whitelistHit =
153 this.isFrameWhitelisted(frames, contentType == "ELEMHIDE");
154 if (whitelistHit)
155 {
156 let [frameIndex, matchType, docDomain, thirdParty, location, filter] = w hitelistHit;
157 addHit(frameIndex, matchType, docDomain, thirdParty, location, filter);
158 if (matchType == "DOCUMENT" || matchType == "ELEMHIDE")
159 return response(true, false);
160 else
161 nogeneric = true;
162 }
163 }
164
165 let match = null;
148 let wndLocation = frames[0].location; 166 let wndLocation = frames[0].location;
149 let docDomain = getHostname(wndLocation); 167 let docDomain = getHostname(wndLocation);
150 let match = null;
151 let [sitekey, sitekeyFrame] = getSitekey(frames); 168 let [sitekey, sitekeyFrame] = getSitekey(frames);
152 let nogeneric = false; 169 if (contentType == "ELEMHIDE")
153 if (!match && Prefs.enabled)
154 {
155 let testSitekey = sitekey;
156 let testSitekeyFrame = sitekeyFrame;
157 for (let i = 0; i < frames.length; i++)
158 {
159 let frame = frames[i];
160 let testWndLocation = frame.location;
161 let parentWndLocation = frames[Math.min(i + 1, frames.length - 1)].locat ion;
162 let parentDocDomain = getHostname(parentWndLocation);
163
164 let typeMap = RegExpFilter.typeMap.DOCUMENT;
165 if (contentType == "ELEMHIDE")
166 typeMap = typeMap | RegExpFilter.typeMap.ELEMHIDE;
167 let whitelistMatch = defaultMatcher.matchesAny(testWndLocation, typeMap, parentDocDomain, false, testSitekey);
168 if (whitelistMatch instanceof WhitelistFilter)
169 {
170 let whitelistType = (whitelistMatch.contentType & RegExpFilter.typeMap .DOCUMENT) ? "DOCUMENT" : "ELEMHIDE";
171 addHit(i, whitelistType, parentDocDomain, false, testWndLocation,
172 whitelistMatch);
173 return response(true, false);
174 }
175
176 let genericType = (contentType == "ELEMHIDE" ? "GENERICHIDE" : "GENERICB LOCK");
177 let nogenericMatch = defaultMatcher.matchesAny(testWndLocation,
178 RegExpFilter.typeMap[genericType], parentDocDomain, false, testSitek ey);
179 if (nogenericMatch instanceof WhitelistFilter)
180 {
181 nogeneric = true;
182 addHit(i, genericType, parentDocDomain, false, testWndLocation,
183 nogenericMatch);
184 }
185
186 if (frame == testSitekeyFrame)
187 [testSitekey, testSitekeyFrame] = getSitekey(frames.slice(i + 1));
188 }
189 }
190
191 if (!match && contentType == "ELEMHIDE")
192 { 170 {
193 match = ElemHide.getFilterByKey(location); 171 match = ElemHide.getFilterByKey(location);
194 location = match.text.replace(/^.*?#/, '#'); 172 location = match.text.replace(/^.*?#/, '#');
195 173
196 if (!match.isActiveOnDomain(docDomain)) 174 if (!match.isActiveOnDomain(docDomain))
197 return response(true, false); 175 return response(true, false);
198 176
199 let exception = ElemHide.getException(match, docDomain); 177 let exception = ElemHide.getException(match, docDomain);
200 if (exception) 178 if (exception)
201 { 179 {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 { 211 {
234 let match = /^([\w\-]+):/.exec(location); 212 let match = /^([\w\-]+):/.exec(location);
235 scheme = match ? match[1] : null; 213 scheme = match ? match[1] : null;
236 } 214 }
237 else 215 else
238 scheme = location.scheme; 216 scheme = location.scheme;
239 return !this.whitelistSchemes.has(scheme); 217 return !this.whitelistSchemes.has(scheme);
240 }, 218 },
241 219
242 /** 220 /**
243 * Checks whether a page is whitelisted. 221 * Checks whether a top-level window is whitelisted.
244 * @param {String} url 222 * @param {String} url
245 * @param {String} [parentUrl] location of the parent page 223 * URL of the document loaded into the window
246 * @param {String} [sitekey] public key provided on the page 224 * @return {?WhitelistFilter}
247 * @return {Filter} filter that matched the URL or null if not whitelisted 225 * exception rule that matched the URL if any
248 */ 226 */
249 isWhitelisted: function(url, parentUrl, sitekey) 227 isWhitelisted: function(url)
250 { 228 {
251 if (!url) 229 if (!url)
252 return null; 230 return null;
253 231
254 // Do not apply exception rules to schemes on our whitelistschemes list. 232 // Do not apply exception rules to schemes on our whitelistschemes list.
255 if (!this.isBlockableScheme(url)) 233 if (!this.isBlockableScheme(url))
256 return null; 234 return null;
257
258 if (!parentUrl)
259 parentUrl = url;
260 235
261 // Ignore fragment identifier 236 // Ignore fragment identifier
262 let index = url.indexOf("#"); 237 let index = url.indexOf("#");
263 if (index >= 0) 238 if (index >= 0)
264 url = url.substring(0, index); 239 url = url.substring(0, index);
265 240
266 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); 241 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT,
242 getHostname(url), false, null);
267 return (result instanceof WhitelistFilter ? result : null); 243 return (result instanceof WhitelistFilter ? result : null);
244 },
245
246 /**
247 * Checks whether a frame is whitelisted.
248 * @param {Array} frames
249 * frame structure as returned by getFrames() in child/utils module.
250 * @param {boolean} isElemHide
251 * true if element hiding whitelisting should be considered
252 * @return {?Array}
253 * An array with the hit parameters: frameIndex, contentType, docDomain,
254 * thirdParty, location, filter. Note that the filter could be a
255 * genericblock/generichide exception rule. If nothing matched null is
256 * returned.
257 */
258 isFrameWhitelisted: function(frames, isElemHide)
259 {
260 let [sitekey, sitekeyFrame] = getSitekey(frames);
261 let nogenericHit = null;
262
263 let typeMap = RegExpFilter.typeMap.DOCUMENT;
264 if (isElemHide)
265 typeMap = typeMap | RegExpFilter.typeMap.ELEMHIDE;
266 let genericType = (isElemHide ? "GENERICHIDE" : "GENERICBLOCK");
267
268 for (let i = 0; i < frames.length; i++)
269 {
270 let frame = frames[i];
271 let wndLocation = frame.location;
272 let parentWndLocation = frames[Math.min(i + 1, frames.length - 1)].locatio n;
273 let parentDocDomain = getHostname(parentWndLocation);
274
275 let match = defaultMatcher.matchesAny(wndLocation, typeMap, parentDocDomai n, false, sitekey);
276 if (match instanceof WhitelistFilter)
277 {
278 let whitelistType = (whitelistMatch.contentType & RegExpFilter.typeMap.D OCUMENT) ? "DOCUMENT" : "ELEMHIDE";
279 return [i, whitelistType, parentDocDomain, false, wndLocation, match];
280 }
281
282 if (!nogenericHit)
283 {
284 match = defaultMatcher.matchesAny(wndLocation,
285 RegExpFilter.typeMap[genericType], parentDocDomain, false, sitekey);
286 if (match instanceof WhitelistFilter)
287 nogenericHit = [i, genericType, parentDocDomain, false, wndLocation, m atch];
288 }
289
290 if (frame == sitekeyFrame)
291 [sitekey, sitekeyFrame] = getSitekey(frames.slice(i + 1));
292 }
293
294 return nogenericHit;
268 }, 295 },
269 296
270 /** 297 /**
271 * Deletes nodes that were previously stored with a 298 * Deletes nodes that were previously stored with a
272 * RequestNotifier.storeNodesForEntries() call or similar. 299 * RequestNotifier.storeNodesForEntries() call or similar.
273 * @param {string} id unique ID of the nodes 300 * @param {string} id unique ID of the nodes
274 */ 301 */
275 deleteNodes: function(id) 302 deleteNodes: function(id)
276 { 303 {
277 let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"] 304 port.emit("deleteNodes", id);
278 .getService(Ci.nsIMessageBroadcaster);
279 messageManager.broadcastAsyncMessage("AdblockPlus:DeleteNodes", id);
280 }, 305 },
281 306
282 /** 307 /**
283 * Asynchronously re-checks filters for nodes given by an ID previously 308 * Asynchronously re-checks filters for nodes given by an ID previously
284 * returned by a RequestNotifier.storeNodesForEntries() call or similar. 309 * returned by a RequestNotifier.storeNodesForEntries() call or similar.
285 * @param {string} id unique ID of the nodes 310 * @param {string} id unique ID of the nodes
286 * @param {RequestEntry} entry 311 * @param {RequestEntry} entry
287 */ 312 */
288 refilterNodes: function(id, entry) 313 refilterNodes: function(id, entry)
289 { 314 {
290 let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"] 315 port.emit("refilterNodes", {
291 .getService(Ci.nsIMessageBroadcaster);
292 messageManager.broadcastAsyncMessage("AdblockPlus:RefilterNodes", {
293 nodesID: id, 316 nodesID: id,
294 entry: entry 317 entry: entry
295 }); 318 });
296 } 319 }
297 }; 320 };
298 Policy.init(); 321 Policy.init();
299 322
300 /** 323 /**
301 * Extracts the hostname from a URL (might return null). 324 * Extracts the hostname from a URL (might return null).
302 */ 325 */
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 { 424 {
402 // EffectiveTLDService throws on IP addresses, just compare the host name 425 // EffectiveTLDService throws on IP addresses, just compare the host name
403 let host = ""; 426 let host = "";
404 try 427 try
405 { 428 {
406 host = uri.host; 429 host = uri.host;
407 } catch (e) {} 430 } catch (e) {}
408 return host != docDomain; 431 return host != docDomain;
409 } 432 }
410 } 433 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld