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

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

Issue 29329654: Issue 3222 - Split up requestNotifier module into a parent and child part (Closed)
Patch Set: Improved comments Created Nov. 12, 2015, 12:40 p.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 | « lib/child/contentPolicy.js ('k') | lib/requestNotifier.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-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 Stores Adblock Plus data to be attached to a window. 19 * @fileOverview Stores Adblock Plus data to be attached to a window.
20 */ 20 */
21 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
21 22
22 let {Utils} = require("utils"); 23 let {Utils} = require("utils");
23 24
24 let nodeData = new WeakMap(); 25 let nodeData = new WeakMap();
25 let windowStats = new WeakMap(); 26 let windowStats = new WeakMap();
26 let windowSelection = new WeakMap();
27 let requestNotifierMaxId = 0;
28 let requestEntryMaxId = 0; 27 let requestEntryMaxId = 0;
29 28
30 /** 29 /**
31 * Active RequestNotifier instances by their ID 30 * Active RequestNotifier instances by their ID
32 * @type Map 31 * @type Map
33 */ 32 */
34 let notifiers = new Map(); 33 let notifiers = new Map();
35 34
35 addMessageListener("AdblockPlus:StartWindowScan", onStartScan);
36 addMessageListener("AdblockPlus:ShutdownNotifier", onNotifierShutdown);
37
38 onShutdown.add(() => {
39 removeMessageListener("AdblockPlus:StartWindowScan", onStartScan);
40 removeMessageListener("AdblockPlus:ShutdownNotifier", onNotifierShutdown);
41 });
42
43 function onStartScan(message)
44 {
45 let {notifierID, outerWindowID} = message.data;
46 let window = Services.wm.getOuterWindowWithId(outerWindowID);
47 if (window)
48 new RequestNotifier(window, notifierID);
49 }
50
51 function onNotifierShutdown(message)
52 {
53 let notifier = notifiers.get(message.data);
54 if (notifier)
55 notifier.shutdown();
56 }
57
36 /** 58 /**
37 * Creates a notifier object for a particular window. After creation the window 59 * Creates a notifier object for a particular window. After creation the window
38 * will first be scanned for previously saved requests. Once that scan is 60 * will first be scanned for previously saved requests. Once that scan is
39 * complete only new requests for this window will be reported. 61 * complete only new requests for this window will be reported.
40 * @param {Window} wnd window to attach the notifier to 62 * @param {Window} window window to attach the notifier to
41 * @param {Function} listener listener to be called whenever a new request is f ound 63 * @param {Integer} notifierID Parent notifier ID to be messaged
42 * @param {Object} [listenerObj] "this" pointer to be used when calling the lis tener
43 */ 64 */
44 function RequestNotifier(wnd, listener, listenerObj) 65 function RequestNotifier(window, notifierID)
45 { 66 {
46 this.window = wnd; 67 this.window = window;
47 this.listener = listener; 68 this.id = notifierID;
48 this.listenerObj = listenerObj || null;
49 this.id = ++requestNotifierMaxId;
50 notifiers.set(this.id, this); 69 notifiers.set(this.id, this);
51 if (wnd) 70 this.startScan(window);
52 this.startScan(wnd);
53 else
54 this.scanComplete = true;
55 } 71 }
56 exports.RequestNotifier = RequestNotifier; 72 exports.RequestNotifier = RequestNotifier;
57 73
58 RequestNotifier.prototype = 74 RequestNotifier.prototype =
59 { 75 {
60 /** 76 /**
61 * The unique ID of this notifier. 77 * Parent notifier ID to be messaged
62 * @type Integer 78 * @type Integer
63 */ 79 */
64 id: null, 80 id: null,
65 81
66 /** 82 /**
67 * The window this notifier is associated with. 83 * The window this notifier is associated with.
68 * @type Window 84 * @type Window
69 */ 85 */
70 window: null, 86 window: null,
71 87
72 /** 88 /**
73 * The listener to be called when a new request is found.
74 * @type Function
75 */
76 listener: null,
77
78 /**
79 * "this" pointer to be used when calling the listener.
80 * @type Object
81 */
82 listenerObj: null,
83
84 /**
85 * Will be set to true once the initial window scan is complete.
86 * @type Boolean
87 */
88 scanComplete: false,
89
90 /**
91 * Shuts down the notifier once it is no longer used. The listener 89 * Shuts down the notifier once it is no longer used. The listener
92 * will no longer be called after that. 90 * will no longer be called after that.
93 */ 91 */
94 shutdown: function() 92 shutdown: function()
95 { 93 {
96 delete this.window; 94 delete this.window;
97 delete this.listener;
98 delete this.listenerObj;
99
100 notifiers.delete(this.id); 95 notifiers.delete(this.id);
101 }, 96 },
102 97
103 /** 98 /**
104 * Notifies listener about a new request. 99 * Notifies the parent about a new request.
105 * @param {Window} wnd
106 * @param {Node} node
107 * @param {Object} entry 100 * @param {Object} entry
108 */ 101 */
109 notifyListener: function(wnd, node, entry) 102 notifyListener: function(entry)
110 { 103 {
111 this.listener.call(this.listenerObj, wnd, node, entry, this.scanComplete); 104 sendAsyncMessage("AdblockPlus:FoundNodeData", {
105 notifierID: this.id,
106 data: entry
107 });
108 },
109
110 onComplete: function()
111 {
112 sendAsyncMessage("AdblockPlus:ScanComplete", this.id);
112 }, 113 },
113 114
114 /** 115 /**
115 * Number of currently posted scan events (will be 0 when the scan finishes 116 * Number of currently posted scan events (will be 0 when the scan finishes
116 * running). 117 * running).
117 */ 118 */
118 eventsPosted: 0, 119 eventsPosted: 0,
119 120
120 /** 121 /**
121 * Starts the initial scan of the window (will recurse into frames). 122 * Starts the initial scan of the window (will recurse into frames).
122 * @param {Window} wnd the window to be scanned 123 * @param {Window} wnd the window to be scanned
123 */ 124 */
124 startScan: function(wnd) 125 startScan: function(wnd)
125 { 126 {
126 let doc = wnd.document; 127 let doc = wnd.document;
127 let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, nul l, false); 128 let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, nul l, false);
128 129
129 let process = function() 130 let process = function()
130 { 131 {
131 if (!this.listener) 132 // Don't do anything if the notifier was shut down already.
133 if (!this.window)
132 return; 134 return;
133 135
134 let node = walker.currentNode; 136 let node = walker.currentNode;
135 let data = nodeData.get(node); 137 let data = nodeData.get(node);
136 if (typeof data != "undefined") 138 if (typeof data != "undefined")
137 for (let k in data) 139 for (let k in data)
138 this.notifyListener(wnd, node, data[k]); 140 this.notifyListener(data[k]);
139 141
140 if (walker.nextNode()) 142 if (walker.nextNode())
141 Utils.runAsync(process); 143 Utils.runAsync(process);
142 else 144 else
143 { 145 {
144 // Done with the current window, start the scan for its frames 146 // Done with the current window, start the scan for its frames
145 for (let i = 0; i < wnd.frames.length; i++) 147 for (let i = 0; i < wnd.frames.length; i++)
146 this.startScan(wnd.frames[i]); 148 this.startScan(wnd.frames[i]);
147 149
148 this.eventsPosted--; 150 this.eventsPosted--;
149 if (!this.eventsPosted) 151 if (!this.eventsPosted)
150 { 152 {
151 this.scanComplete = true; 153 this.scanComplete = true;
152 this.notifyListener(wnd, null, null); 154 this.onComplete();
153 } 155 }
154 } 156 }
155 }.bind(this); 157 }.bind(this);
156 158
157 // Process each node in a separate event to allow other events to process 159 // Process each node in a separate event to allow other events to process
158 this.eventsPosted++; 160 this.eventsPosted++;
159 Utils.runAsync(process); 161 Utils.runAsync(process);
160 } 162 }
161 }; 163 };
162 164
163 RequestNotifier.storeSelection = function(/**Window*/ wnd, /**String*/ selection )
164 {
165 windowSelection.set(wnd.document, selection);
166 };
167 RequestNotifier.getSelection = function(/**Window*/ wnd) /**String*/
168 {
169 if (windowSelection.has(wnd.document))
170 return windowSelection.get(wnd.document);
171 else
172 return null;
173 };
174
175 /** 165 /**
176 * Attaches request data to a DOM node. 166 * Attaches request data to a DOM node.
177 * @param {Node} node node to attach data to 167 * @param {Node} node node to attach data to
178 * @param {Window} topWnd top-level window the node belongs to 168 * @param {Window} topWnd top-level window the node belongs to
179 * @param {String} contentType request type, e.g. "IMAGE" 169 * @param {String} contentType request type, e.g. "IMAGE"
180 * @param {String} docDomain domain of the document that initiated the request 170 * @param {String} docDomain domain of the document that initiated the request
181 * @param {Boolean} thirdParty will be true if a third-party server has been re quested 171 * @param {Boolean} thirdParty will be true if a third-party server has been re quested
182 * @param {String} location the address that has been requested 172 * @param {String} location the address that has been requested
183 * @param {Filter} filter filter applied to the request or null if none 173 * @param {Filter} filter filter applied to the request or null if none
184 */ 174 */
185 RequestNotifier.addNodeData = function(/**Node*/ node, /**Window*/ topWnd, /**St ring*/ contentType, /**String*/ docDomain, /**Boolean*/ thirdParty, /**String*/ location, /**Filter*/ filter) 175 RequestNotifier.addNodeData = function(/**Node*/ node, /**Window*/ topWnd, /**St ring*/ contentType, /**String*/ docDomain, /**Boolean*/ thirdParty, /**String*/ location, /**Filter*/ filter)
186 { 176 {
187 let entry = { 177 let entry = {
188 id: ++requestEntryMaxId, 178 id: ++requestEntryMaxId,
189 type: contentType, 179 type: contentType,
190 docDomain, thirdParty, location, filter 180 docDomain, thirdParty, location, filter
191 } 181 };
192 182
193 let existingData = nodeData.get(node); 183 let existingData = nodeData.get(node);
194 if (typeof existingData == "undefined") 184 if (typeof existingData == "undefined")
195 { 185 {
196 existingData = {}; 186 existingData = {};
197 nodeData.set(node, existingData); 187 nodeData.set(node, existingData);
198 } 188 }
199 189
200 // Add this request to the node data 190 // Add this request to the node data
201 existingData[contentType + " " + location] = entry; 191 existingData[contentType + " " + location] = entry;
(...skipping 25 matching lines...) Expand all
227 217
228 if (filter.text in stats.filters) 218 if (filter.text in stats.filters)
229 stats.filters[filter.text]++; 219 stats.filters[filter.text]++;
230 else 220 else
231 stats.filters[filter.text] = 1; 221 stats.filters[filter.text] = 1;
232 } 222 }
233 223
234 // Notify listeners 224 // Notify listeners
235 for (let notifier of notifiers.values()) 225 for (let notifier of notifiers.values())
236 if (!notifier.window || notifier.window == topWnd) 226 if (!notifier.window || notifier.window == topWnd)
237 notifier.notifyListener(topWnd, node, entry); 227 notifier.notifyListener(entry);
238 } 228 }
239
240 /**
241 * Retrieves the statistics for a window.
242 * @result {Object} Object with the properties items, blocked, whitelisted, hidd en, filters containing statistics for the window (might be null)
243 */
244 RequestNotifier.getWindowStatistics = function(/**Window*/ wnd)
245 {
246 if (windowStats.has(wnd.document))
247 return windowStats.get(wnd.document);
248 else
249 return null;
250 }
251
252 /**
253 * Retrieves the request data associated with a DOM node.
254 * @param {Node} node
255 * @param {Boolean} noParent if missing or false, the search will extend to the parent nodes until one is found that has data associated with it
256 * @param {Integer} [type] request type to be looking for
257 * @param {String} [location] request location to be looking for
258 * @result {[Node, Object]}
259 * @static
260 */
261 RequestNotifier.getDataForNode = function(node, noParent, type, location)
262 {
263 while (node)
264 {
265 let data = nodeData.get(node);
266 if (typeof data != "undefined")
267 {
268 let entry = null;
269 // Look for matching entry
270 for (let k in data)
271 {
272 if ((!entry || entry.id < data[k].id) &&
273 (typeof type == "undefined" || data[k].type == type) &&
274 (typeof location == "undefined" || data[k].location == location))
275 {
276 entry = data[k];
277 }
278 }
279 if (entry)
280 return [node, entry];
281 }
282
283 // If we don't have any match on this node then maybe its parent will do
284 if ((typeof noParent != "boolean" || !noParent) &&
285 node.parentNode instanceof Ci.nsIDOMElement)
286 {
287 node = node.parentNode;
288 }
289 else
290 {
291 node = null;
292 }
293 }
294
295 return null;
296 };
OLDNEW
« no previous file with comments | « lib/child/contentPolicy.js ('k') | lib/requestNotifier.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld