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

Side by Side Diff: chrome/content/watcher.js

Issue 29331940: Issue 3225 - Make Diagnostics compatible with the upcoming Adblock Plus 2.7 release (Closed)
Patch Set: Track filter hits properly Created Dec. 7, 2015, 12:15 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 | « no previous file | chrome/content/watcher.xul » ('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 Source Code is subject to the terms of the Mozilla Public License 2 * This Source Code is subject to the terms of the Mozilla Public License
3 * version 2.0 (the "License"). You can obtain a copy of the License at 3 * version 2.0 (the "License"). You can obtain a copy of the License at
4 * http://mozilla.org/MPL/2.0/. 4 * http://mozilla.org/MPL/2.0/.
5 */ 5 */
6 6
7 const Cc = Components.classes; 7 const Cc = Components.classes;
8 const Ci = Components.interfaces; 8 const Ci = Components.interfaces;
9 const Cr = Components.results; 9 const Cr = Components.results;
10 const Cu = Components.utils; 10 const Cu = Components.utils;
11 11
12 Cu.import("resource://gre/modules/Services.jsm"); 12 Cu.import("resource://gre/modules/Services.jsm");
13 13
14 function abprequire(module) 14 function abprequire(module)
15 { 15 {
16 let result = {}; 16 let result = {};
17 result.wrappedJSObject = result; 17 result.wrappedJSObject = result;
18 Services.obs.notifyObservers(result, "adblockplus-require", module); 18 Services.obs.notifyObservers(result, "adblockplus-require", module);
19 return result.exports; 19 return result.exports;
20 } 20 }
21 21
22 let {Policy} = abprequire("contentPolicy"); 22 let {Policy} = abprequire("contentPolicy");
23 let {RequestNotifier} = abprequire("requestNotifier");
24 let {Filter} = abprequire("filterClasses"); 23 let {Filter} = abprequire("filterClasses");
25 24
26 let policyGlobal = Cu.getGlobalForObject(Policy); 25 let origShouldAllow = Policy.shouldAllow;
27 let PolicyPrivate = null; 26 if (!origShouldAllow)
28
29 if ("PolicyImplementation" in policyGlobal) // ABP 2.1+ with scope separation
30 PolicyPrivate = policyGlobal.PolicyImplementation;
31 else if ("require" in policyGlobal) // ABP 2.1+ without scope sepa ration
32 PolicyPrivate = policyGlobal.require.scopes.contentPolicy.PolicyImplementation ;
33 else
34 window.close(); 27 window.close();
35 28
36 let origShouldLoad = PolicyPrivate.shouldLoad;
37 let origProcessNode = Policy.processNode;
38
39 let currentData = null; 29 let currentData = null;
Thomas Greiner 2015/12/07 15:24:20 `currentData` is no longer used across multiple fu
Wladimir Palant 2015/12/07 15:37:55 Done.
40 let processingQueue = []; 30 let processingQueue = [];
41 let notifier = null; 31 let notifier = null;
42 32
43 // Randomize URI to work around bug 719376 33 // Randomize URI to work around bug 719376
44 let stringBundle = Services.strings.createBundle("chrome://abpwatcher/locale/glo bal.properties?" + Math.random()); 34 let stringBundle = Services.strings.createBundle("chrome://abpwatcher/locale/glo bal.properties?" + Math.random());
45 35
46 let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci. nsIClipboardHelper); 36 let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci. nsIClipboardHelper);
47 37
48 function init() 38 function init()
49 { 39 {
50 let list = document.getElementById("list"); 40 let list = document.getElementById("list");
51 list.view = treeView; 41 list.view = treeView;
52 list.focus(); 42 list.focus();
53 43
54 treeView.addObserver(updateProcessingTime); 44 treeView.addObserver(updateProcessingTime);
55 updateProcessingTime(treeView, "refresh"); 45 updateProcessingTime(treeView, "refresh");
56 46
57 // Make sure the tree view has correct filters 47 // Make sure the tree view has correct filters
58 document.getElementById("ignore-early").doCommand();
59 document.getElementById("filterText").doCommand(); 48 document.getElementById("filterText").doCommand();
60 49
61 notifier = new RequestNotifier(null, handleFilterHit); 50 Policy.shouldAllow = replacementShouldAllow;
62
63 PolicyPrivate.shouldLoad = replacementShouldLoad;
64 Policy.processNode = replacementProcessNode;
65 setInterval(processQueue, 200); 51 setInterval(processQueue, 200);
66 } 52 }
67 53
68 function E(id) 54 function E(id)
69 { 55 {
70 return document.getElementById(id); 56 return document.getElementById(id);
71 } 57 }
72 58
73 function replacementShouldLoad(contentType, contentLocation, requestOrigin, node , mimeTypeGuess, extra) 59 function replacementShouldAllow({contentType, location, frames, isPrivate})
74 { 60 {
75 let startTime = null; 61 let startTime = null;
76 try 62 try
77 { 63 {
78 currentData = {internal: false, earlyReturn: true, filters: []}; 64 currentData = {
65 type: contentType,
66 location: location,
67 frames: frames,
68 isPrivate: isPrivate
69 };
79 startTime = Date.now(); 70 startTime = Date.now();
80
81 if (contentLocation)
82 currentData.location = contentLocation.spec;
83 if (requestOrigin)
84 currentData.origin = requestOrigin.spec;
85
86 currentData.type = contentType;
87 } catch(e) {}
88
89 let ret;
90 try
91 {
92 ret = origShouldLoad.apply(this, arguments);
93 return ret;
94 }
95 finally
96 {
97 if (startTime !== null)
98 currentData.processingTime = (Date.now() - startTime);
99 currentData.result = (ret == Ci.nsIContentPolicy.ACCEPT);
100
101 processingQueue.push(currentData);
102 currentData = null;
103 }
104 }
105
106 function replacementProcessNode(wnd, node, contentType, location, collapse)
107 {
108 let startTime = null;
109 try
110 {
111 if (currentData && !("context" in currentData))
112 {
113 currentData.earlyReturn = false;
114 currentData.context = node;
115 currentData.window = wnd;
116 currentData.internalType = contentType;
117 if (location)
118 currentData.internalLocation = location.spec;
119 }
120 else
121 {
122 // shouldLoad wasn't called - this isn't being called by content policy
123 let locationString = (location instanceof Filter ? location.text : locatio n.spec);
124
125 currentData = {
126 internal: true,
127 earlyReturn: false,
128 filters: [],
129 location: locationString,
130 internalLocation: locationString,
131 context: node,
132 window: wnd,
133 type: contentType,
134 internalType: contentType
135 };
136 startTime = Date.now();
137 }
138 } 71 }
139 catch(e) 72 catch(e)
140 { 73 {
141 Cu.reportError(e); 74 Cu.reportError(e);
142 } 75 }
143 76
144 let ret; 77 let ret;
145 try 78 try
146 { 79 {
147 ret = origProcessNode.apply(this, arguments); 80 ret = origShouldAllow.apply(this, arguments);
148 return ret; 81 return ret;
149 } 82 }
150 finally 83 finally
151 { 84 {
152 if (startTime !== null) 85 if (startTime !== null)
153 { 86 {
154 currentData.processingTime = (Date.now() - startTime); 87 currentData.processingTime = (Date.now() - startTime);
155 currentData.result = (ret == true); 88 currentData.result = ret;
89 currentData.filters = ret.hits.filter(h => h.filter).map(h => h.filter);
156 90
157 processingQueue.push(currentData); 91 processingQueue.push(currentData);
158 currentData = null; 92 currentData = null;
159 } 93 }
160 } 94 }
161 } 95 }
162 96
163 function destroy() 97 function destroy()
164 { 98 {
165 if (notifier) 99 if (origShouldAllow)
166 notifier.shutdown(); 100 Policy.shouldAllow = origShouldAllow;
167 if (origShouldLoad)
168 PolicyPrivate.shouldLoad = origShouldLoad;
169 if (origProcessNode)
170 Policy.processNode = origProcessNode;
171 }
172
173 function handleFilterHit(wnd, node, data)
174 {
175 if (data.filter && currentData)
176 currentData.filters.push(data.filter.text);
177 } 101 }
178 102
179 function processQueue() 103 function processQueue()
180 { 104 {
181 if (!processingQueue.length) 105 if (!processingQueue.length)
182 return; 106 return;
183 107
108 function stringify(value)
109 {
110 if (typeof value == "undefined" || value == null)
111 return "";
112 else
113 return String(value);
114 }
115
184 for each (let entry in processingQueue) 116 for each (let entry in processingQueue)
185 { 117 {
186 entry.cols = {}; 118 entry.cols = {
187 if (typeof entry.location != "undefined") 119 address: stringify(entry.location),
188 entry.cols.address = String(entry.location); 120 type: stringify(entry.type),
189 if (typeof entry.type != "undefined") 121 result: stringBundle.GetStringFromName(entry.result && entry.result.allow ? "decision.allow" : "decision.block"),
190 { 122 origin: stringify(entry.frames && entry.frames[0] && entry.frames[0].locat ion),
191 entry.cols.type = String(entry.type); 123 filter: stringify(entry.filters && entry.filters.join(", ")),
192 try { 124 time: stringify(entry.processingTime)
193 // Nasty hack: try to get type name from ABP 125 };
194 if (entry.type in Policy.localizedDescr)
195 entry.cols.type = String(Policy.localizedDescr[entry.type]);
Thomas Greiner 2015/12/07 15:24:20 I know that it is no longer done in the content po
Wladimir Palant 2015/12/07 15:37:55 Right, I forgot to mention that. Yes, this was don
196 } catch(e) {}
197 }
198 entry.cols.result = stringBundle.GetStringFromName(entry.result ? "decision. allow" : "decision.block");
199 if (typeof entry.context != "undefined")
200 entry.cols.context = (entry.context ? getNodeLabel(entry.context) : String (entry.context));
201 if (typeof entry.window != "undefined")
202 entry.cols.document = (entry.window ? getNodeLabel(entry.window) : String( entry.window));
203 if (typeof entry.origin != "undefined")
204 entry.cols.origin = String(entry.origin);
205 if (entry.filters.length)
206 entry.cols.filter = entry.filters.join(", ");
207 if (typeof entry.processingTime != "undefined")
208 entry.cols.time = String(entry.processingTime);
209
210 let additional = [];
211 if (entry.internal)
212 additional.push(stringBundle.GetStringFromName("additional.internalInvocat ion"));
213 if (typeof entry.internalType != "undefined" && entry.type != entry.internal Type)
214 {
215 let internalType = String(entry.internalType);
216 try {
217 // Nasty hack: try to get type name from ABP
218 if (entry.internalType in Policy.localizedDescr)
219 internalType = String(Policy.localizedDescr[entry.internalType]);
220 } catch(e) {}
221 additional.push(stringBundle.formatStringFromName("additional.typeChanged" , [internalType], 1));
222 }
223 if (typeof entry.internalLocation != "undefined" && entry.location != entry. internalLocation)
224 additional.push(stringBundle.formatStringFromName("additional.locationChan ged", [String(entry.internalLocation)], 1));
225
226 if (additional.length > 0)
227 entry.cols.additional = additional.join(", ");
228
229 treeView.add(entry); 126 treeView.add(entry);
230 } 127 }
231 128
232 processingQueue = []; 129 processingQueue = [];
233 } 130 }
234 131
235 function getNodeLabel(node)
236 {
237 try
238 {
239 if (node instanceof Ci.nsIDOMWindow)
240 return stringBundle.formatStringFromName("NodeLabel.window", [node.locatio n.href], 1);
241 if (node instanceof Ci.nsIDOMDocument)
242 return stringBundle.formatStringFromName("NodeLabel.document", [node.URL], 1);
243 else if (node instanceof Ci.nsIDOMXULElement)
244 return stringBundle.formatStringFromName("NodeLabel.xulElement", [node.tag Name], 1);
245 else if (node instanceof Ci.nsIDOMHTMLElement)
246 return stringBundle.formatStringFromName("NodeLabel.htmlElement", [node.ta gName], 1);
247 else if (node instanceof Ci.nsIDOMSVGElement)
248 return stringBundle.formatStringFromName("NodeLabel.svgElement", [node.tag Name], 1);
249 else if (node instanceof Ci.nsIDOMElement)
250 return stringBundle.formatStringFromName("NodeLabel.element", [node.tagNam e], 1);
251 else
252 return stringBundle.formatStringFromName("NodeLabel.unknown", [String(node )], 1);
253 }
254 catch (e)
255 {
256 Cu.reportError(e);
257 return stringBundle.formatStringFromName("NodeLabel.unknown", [""], 1);
258 }
259 }
260
261 function fillInTooltip(event) 132 function fillInTooltip(event)
262 { 133 {
263 let entry = treeView.getEntryAt(event.clientX, event.clientY); 134 let entry = treeView.getEntryAt(event.clientX, event.clientY);
264 if (!entry) 135 if (!entry)
265 return false; 136 return false;
266 137
267 let rows = document.getElementById("tooltip-rows"); 138 let rows = document.getElementById("tooltip-rows");
268 while (rows.firstChild) 139 while (rows.firstChild)
269 rows.removeChild(rows.firstChild); 140 rows.removeChild(rows.firstChild);
270 141
271 let cols = document.getElementById("list").getElementsByTagName("treecol"); 142 let cols = document.getElementById("list").getElementsByTagName("treecol");
272 for (let i = 0; i < cols.length; i++) 143 for (let i = 0; i < cols.length; i++)
273 { 144 {
274 let col = cols[i].id; 145 let col = cols[i].id;
275 if (col && col in entry.cols) 146 if (col && col in entry.cols)
276 { 147 {
277 let row = document.createElement("row"); 148 let row = document.createElement("row");
278 149
279 let label = document.createElement("description"); 150 let label = document.createElement("description");
280 label.setAttribute("class", "tooltip-label"); 151 label.setAttribute("class", "tooltip-label");
281 label.setAttribute("value", cols[i].getAttribute("label")); 152 label.setAttribute("value", cols[i].getAttribute("label"));
282 row.appendChild(label); 153 row.appendChild(label);
283 154
284 let value = document.createElement("vbox"); 155 let value = document.createElement("vbox");
285 setMultilineContent(value, entry.cols[col]); 156 let data = entry.cols[col];
157 if (col == "origin")
158 data = entry.frames.map(f => f.location).join("\n");
159 setMultilineContent(value, data);
286 row.appendChild(value); 160 row.appendChild(value);
287 161
288 rows.appendChild(row); 162 rows.appendChild(row);
289 } 163 }
290 } 164 }
291 165
292 return true; 166 return true;
293 } 167 }
294 168
295 function updateContextMenu(event) 169 function updateContextMenu(event)
(...skipping 14 matching lines...) Expand all
310 clipboardHelper.copyString(String(entry.location)); 184 clipboardHelper.copyString(String(entry.location));
311 } 185 }
312 186
313 function copyFilters() 187 function copyFilters()
314 { 188 {
315 let entry = treeView.getCurrentEntry(); 189 let entry = treeView.getCurrentEntry();
316 if (entry && entry.filters.length) 190 if (entry && entry.filters.length)
317 clipboardHelper.copyString(entry.filters.join("\n")); 191 clipboardHelper.copyString(entry.filters.join("\n"));
318 } 192 }
319 193
320 function setMultilineContent(box, text) { 194 function setMultilineContent(box, text)
321 // The following is sufficient in Gecko 1.9 but Gecko 1.8 fails on multiline 195 {
322 // text fields in tooltips 196 let lines = text.split(/\n+/);
323 // box.textContent = text.replace(/\S{80}(?=\S)/g, "$& "); 197 for (let line of lines)
324 198 {
325 for (let i = 0; i < text.length; i += 80) {
326 let description = document.createElement("description"); 199 let description = document.createElement("description");
327 description.setAttribute("value", text.substr(i, 80)); 200 description.textContent = line.replace(/\S{80}(?=\S)/g, "$& ");
328 box.appendChild(description); 201 box.appendChild(description);
329 } 202 }
330 } 203 }
331 204
332 var totalProcessingTime = 0; 205 var totalProcessingTime = 0;
333 function updateProcessingTime(view, operation, entry) 206 function updateProcessingTime(view, operation, entry)
334 { 207 {
335 if (operation == "add") 208 if (operation == "add")
336 totalProcessingTime += entry.processingTime; 209 totalProcessingTime += entry.processingTime;
337 else { 210 else {
338 totalProcessingTime = 0; 211 totalProcessingTime = 0;
339 for each (let entry in view.displayedItems) 212 for each (let entry in view.displayedItems)
340 totalProcessingTime += entry.processingTime; 213 totalProcessingTime += entry.processingTime;
341 } 214 }
342 215
343 let numItems = view.displayedItems.length; 216 let numItems = view.displayedItems.length;
344 217
345 let summary = document.getElementById("summary"); 218 let summary = document.getElementById("summary");
346 let template = summary.getAttribute("_template"); 219 let template = summary.getAttribute("_template");
347 summary.textContent = template.replace(/\*NUMITEMS\*/g, numItems).replace(/\*T IME\*/, (totalProcessingTime / 1000).toFixed(3)); 220 summary.textContent = template.replace(/\*NUMITEMS\*/g, numItems).replace(/\*T IME\*/, (totalProcessingTime / 1000).toFixed(3));
348 } 221 }
349 222
350 var treeView = { 223 var treeView = {
351 currentItems: [], 224 currentItems: [],
352 displayedItems: [], 225 displayedItems: [],
353 _ignoreEarlyReturns: false,
354 _filterString: "", 226 _filterString: "",
355 _sortColumn: null, 227 _sortColumn: null,
356 _sortDirection: null, 228 _sortDirection: null,
357 boxObject: null, 229 boxObject: null,
358 atoms: {}, 230 atoms: {},
359 observers: [], 231 observers: [],
360 232
361 // 233 //
362 // nsISupports implementation 234 // nsISupports implementation
363 // 235 //
(...skipping 15 matching lines...) Expand all
379 selection: null, 251 selection: null,
380 252
381 setTree: function(boxObject) 253 setTree: function(boxObject)
382 { 254 {
383 if (!boxObject) 255 if (!boxObject)
384 return; 256 return;
385 257
386 this.boxObject = boxObject; 258 this.boxObject = boxObject;
387 259
388 let atomService = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomSer vice); 260 let atomService = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomSer vice);
389 for each (let col in ["address", "type", "result", "context", "document", "o rigin", "additional", "filter", "time"]) 261 for each (let col in ["address", "type", "result", "origin", "filter", "time "])
390 { 262 {
391 let atomStr = "col-" + col; 263 let atomStr = "col-" + col;
392 this.atoms[atomStr] = atomService.getAtom(atomStr); 264 this.atoms[atomStr] = atomService.getAtom(atomStr);
393 } 265 }
394 for each (let flag in ["selected", "blocked"]) 266 for each (let flag in ["selected", "blocked"])
395 { 267 {
396 let atomStr = flag + "-true"; 268 let atomStr = flag + "-true";
397 this.atoms[atomStr] = atomService.getAtom(atomStr); 269 this.atoms[atomStr] = atomService.getAtom(atomStr);
398 270
399 atomStr = flag + "-false"; 271 atomStr = flag + "-false";
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 }, 326 },
455 327
456 getRowProperties: function(row, properties) 328 getRowProperties: function(row, properties)
457 { 329 {
458 if (row < 0 || row >= this.displayedItems.length) 330 if (row < 0 || row >= this.displayedItems.length)
459 return ""; 331 return "";
460 332
461 let entry = this.displayedItems[row]; 333 let entry = this.displayedItems[row];
462 return this.generateProperties([ 334 return this.generateProperties([
463 "selected-" + this.selection.isSelected(row), 335 "selected-" + this.selection.isSelected(row),
464 "blocked-" + !entry.result 336 "blocked-" + !(entry.result && entry.result.allow)
465 ], properties); 337 ], properties);
466 }, 338 },
467 339
468 getCellProperties: function(row, col, properties) 340 getCellProperties: function(row, col, properties)
469 { 341 {
470 return this.getRowProperties(row, properties) + " " + this.getColumnProperti es(col, properties); 342 return this.getRowProperties(row, properties) + " " + this.getColumnProperti es(col, properties);
471 }, 343 },
472 344
473 cycleHeader: function(col) 345 cycleHeader: function(col)
474 { 346 {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 cycleCell: function() {}, 396 cycleCell: function() {},
525 performAction: function() {}, 397 performAction: function() {},
526 performActionOnRow: function() {}, 398 performActionOnRow: function() {},
527 performActionOnCell: function() {}, 399 performActionOnCell: function() {},
528 selectionChanged: function() {}, 400 selectionChanged: function() {},
529 401
530 // 402 //
531 // Custom methods 403 // Custom methods
532 // 404 //
533 405
534 get ignoreEarlyReturns()
535 {
536 return this._ignoreEarlyReturns;
537 },
538 set ignoreEarlyReturns(value)
539 {
540 this._ignoreEarlyReturns = value;
541 this.refilter();
542 },
543
544 get filterString() 406 get filterString()
545 { 407 {
546 return this._filterString; 408 return this._filterString;
547 }, 409 },
548 set filterString(value) 410 set filterString(value)
549 { 411 {
550 this._filterString = value.toLowerCase(); 412 this._filterString = value.toLowerCase();
551 this.refilter(); 413 this.refilter();
552 }, 414 },
553 415
554 filter: function(entry) 416 filter: function(entry)
555 { 417 {
556 if (this._ignoreEarlyReturns && entry.earlyReturn)
557 return false;
558
559 if (this._filterString) 418 if (this._filterString)
560 { 419 {
561 let foundMatch = false; 420 let foundMatch = false;
562 for each (let label in entry.cols) 421 for each (let label in entry.cols)
563 if (label.toLowerCase().indexOf(this._filterString) >= 0) 422 if (label.toLowerCase().indexOf(this._filterString) >= 0)
564 foundMatch = true; 423 foundMatch = true;
565 424
566 if (!foundMatch) 425 if (!foundMatch)
567 return false; 426 return false;
568 } 427 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 for (let i = 0; i < this.observers.length; i++) 537 for (let i = 0; i < this.observers.length; i++)
679 if (this.observers[i] == observer) 538 if (this.observers[i] == observer)
680 this.observers.splice(i--, 1); 539 this.observers.splice(i--, 1);
681 }, 540 },
682 notifyObservers: function(operation, entry) 541 notifyObservers: function(operation, entry)
683 { 542 {
684 for each (let observer in this.observers) 543 for each (let observer in this.observers)
685 observer(this, operation, entry); 544 observer(this, operation, entry);
686 } 545 }
687 }; 546 };
OLDNEW
« no previous file with comments | « no previous file | chrome/content/watcher.xul » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld