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

Side by Side Diff: safari/contentBlocking.js

Issue 29503587: Issue 5464 - Upgrade to new asynchronous version of abp2blocklist (Closed) Base URL: https://hg.adblockplus.org/adblockpluschrome/
Patch Set: Created Aug. 2, 2017, 10:47 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
« dependencies ('K') | « dependencies ('k') | no next file » | 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-2017 eyeo GmbH 3 * Copyright (C) 2006-2017 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
(...skipping 19 matching lines...) Expand all
30 { 30 {
31 function onLegacyAPISupported(msg, sender) 31 function onLegacyAPISupported(msg, sender)
32 { 32 {
33 port.off("safari.legacyAPISupported", onLegacyAPISupported); 33 port.off("safari.legacyAPISupported", onLegacyAPISupported);
34 resolve(msg.legacyAPISupported); 34 resolve(msg.legacyAPISupported);
35 } 35 }
36 port.on("safari.legacyAPISupported", onLegacyAPISupported); 36 port.on("safari.legacyAPISupported", onLegacyAPISupported);
37 }); 37 });
38 let contentBlockingActive = false; 38 let contentBlockingActive = false;
39 let afterContentBlockingFinished = null; 39 let afterContentBlockingFinished = null;
40 let pendingContentBlockerUpdate = null;
40 let contentBlockListDirty = true; 41 let contentBlockListDirty = true;
41 let lastSetContentBlockerError; 42 let lastSetContentBlockerError;
42 43
43 function clearBlockCounters() 44 function clearBlockCounters()
44 { 45 {
45 ext.pages.query({}, pages => 46 ext.pages.query({}, pages =>
46 { 47 {
47 for (let page of pages) 48 for (let page of pages)
48 page.browserAction.setBadge(); 49 page.browserAction.setBadge();
49 }); 50 });
50 } 51 }
51 52
52 function setContentBlocker(callback) 53 function setContentBlocker()
53 { 54 {
54 // When given the same rules as last time setContentBlocker will always give 55 return new Promise((resolve, reject) =>
Manish Jethani 2017/08/02 10:55:11 I made this a promise now because it feels more na
55 // null (success) to the callback, even when there was actually an error. We
56 // cache the last result therefore so that we can provide a consistent result
57 // and also to avoid wastefully regenerating an identical blocklist.
58 if (!contentBlockListDirty)
59 { 56 {
60 callback(lastSetContentBlockerError); 57 // Reset state and either fulfill or reject this promise.
61 return; 58 let completePromise = error =>
62 } 59 {
60 lastSetContentBlockerError = error;
61 contentBlockListDirty = false;
63 62
64 let contentBlockerList = new ContentBlockerList(); 63 if (error)
65 for (let subscription of FilterStorage.subscriptions) 64 reject(error);
66 if (!subscription.disabled) 65 else
67 for (let filter of subscription.filters) 66 resolve();
68 contentBlockerList.addFilter(filter); 67 };
69 68
70 contentBlockListDirty = false; 69 // When given the same rules as last time setContentBlocker will always
71 safari.extension.setContentBlocker( 70 // resolve with null (success), even when there was actually an
72 // There is a strange bug in setContentBlocker for Safari 9 where if both 71 // error. We cache the last result therefore so that we can provide a
73 // the callback parameter is provided and the rules aren't converted to a 72 // consistent result and also to avoid wastefully regenerating an identical
74 // JSON string it fails. Worse still it actually performs the callback twice 73 // blocklist.
75 // too, firstly with an empty string and then with an Error: 74 if (!contentBlockListDirty)
76 // "Extension compilation failed: Failed to parse the JSON String."
77 // To mitigate this we convert the rules to JSON here and also ignore
78 // callback values of "". (Usually the callback is performed with either
79 // null for success or an Error on failure.)
80 // Bug #26322821 filed on bugreport.apple.com
81 JSON.stringify(contentBlockerList.generateRules()),
82 function(error)
83 { 75 {
84 if (error == "") 76 completePromise(lastSetContentBlockerError);
85 return; 77 return;
78 }
86 79
87 lastSetContentBlockerError = error; 80 let contentBlockerList = new ContentBlockerList();
88 callback(error); 81 for (let subscription of FilterStorage.subscriptions)
82 {
Manish Jethani 2017/08/02 10:55:11 Added some extra braces as per our style guide.
83 if (!subscription.disabled)
84 {
85 for (let filter of subscription.filters)
86 contentBlockerList.addFilter(filter);
87 }
89 } 88 }
90 ); 89
90 contentBlockerList.generateRules().then(rules =>
91 {
92 safari.extension.setContentBlocker(
93 // There is a strange bug in setContentBlocker for Safari 9 where if
94 // both the callback parameter is provided and the rules aren't
95 // converted to a JSON string it fails. Worse still it actually
96 // performs the callback twice too, firstly with an empty string and
97 // then with an Error: "Extension compilation failed: Failed to parse
98 // the JSON String." To mitigate this we convert the rules to JSON here
99 // and also ignore callback values of "". (Usually the callback is
100 // performed with either null for success or an Error on failure.)
101 // Bug #26322821 filed on bugreport.apple.com
102 JSON.stringify(rules),
103 function(error)
104 {
105 if (error == "")
106 return;
107
108 completePromise(error);
109 }
110 );
111 })
112 .catch(completePromise);
113 });
91 } 114 }
92 115
93 function updateContentBlocker(isStartup, legacyAPISupported) 116 function updateContentBlocker(isStartup, legacyAPISupported)
94 { 117 {
118 // Another update can be requested while one is still in progress (e.g. the
119 // user adds filter lists in quick succession). When this happens, save the
120 // request and execute it later.
121 if (afterContentBlockingFinished)
122 {
123 pendingContentBlockerUpdate = {
Manish Jethani 2017/08/02 10:55:11 Note that we only need to save the last request. W
124 params: Array.from(arguments),
125 // Save the current dirty state so we can set it later before calling
126 // this function again.
127 setDirty: contentBlockListDirty
128 };
129 return;
130 }
131
95 afterContentBlockingFinished = new Promise(resolve => 132 afterContentBlockingFinished = new Promise(resolve =>
96 { 133 {
97 setContentBlocker(error => 134 let setContentBlockerHandler = error =>
98 { 135 {
99 if (error instanceof Error) 136 if (error instanceof Error)
100 { 137 {
101 let suppressErrorMessage = false; 138 let suppressErrorMessage = false;
102 139
103 // If the content blocking API fails the first time it's used the 140 // If the content blocking API fails the first time it's used the
104 // legacy blocking API (if available) won't have been disabled. 141 // legacy blocking API (if available) won't have been disabled.
105 if (!contentBlockingActive && legacyAPISupported) 142 if (!contentBlockingActive && legacyAPISupported)
106 { 143 {
107 Prefs.safariContentBlocker = false; 144 Prefs.safariContentBlocker = false;
108 // If content blocking failed on startup and we're switching back to 145 // If content blocking failed on startup and we're switching back to
109 // the legacy API anyway we don't need to show an error message. 146 // the legacy API anyway we don't need to show an error message.
110 if (isStartup) 147 if (isStartup)
111 suppressErrorMessage = true; 148 suppressErrorMessage = true;
112 } 149 }
113 150
114 if (!suppressErrorMessage) 151 if (!suppressErrorMessage)
115 alert(error.message); 152 alert(error.message);
116 } 153 }
117 else if (!contentBlockingActive) 154 else if (!contentBlockingActive)
118 { 155 {
119 contentBlockingActive = true; 156 contentBlockingActive = true;
120 clearBlockCounters(); 157 clearBlockCounters();
121 } 158 }
122 159
160 afterContentBlockingFinished = null;
Manish Jethani 2017/08/02 10:55:11 This should be set to null before fulfilling the p
123 resolve(contentBlockingActive); 161 resolve(contentBlockingActive);
124 afterContentBlockingFinished = null; 162 };
125 }); 163
164 // There's no need for a catch handler at the end because the handler is
165 // not expected to throw any errors. If this changes, however, then the
166 // error must be handled appropriately.
167 setContentBlocker().then(setContentBlockerHandler,
168 setContentBlockerHandler);
169 })
170 .then(active =>
171 {
172 // If there's another update pending, execute it now.
173 if (pendingContentBlockerUpdate)
174 {
175 let {params, setDirty} = pendingContentBlockerUpdate;
176 pendingContentBlockerUpdate = null;
177
178 if (setDirty)
179 contentBlockListDirty = true;
180
181 updateContentBlocker.apply(null, params);
182 return afterContentBlockingFinished;
183 }
184
185 return active;
126 }); 186 });
127 } 187 }
128 188
129 if (contentBlockingSupported) 189 if (contentBlockingSupported)
130 { 190 {
131 Promise.all([Prefs.untilLoaded, 191 Promise.all([Prefs.untilLoaded,
132 FilterNotifier.once("load"), 192 FilterNotifier.once("load"),
133 legacyAPISupported]).then(resolvedValues => 193 legacyAPISupported]).then(resolvedValues =>
134 { 194 {
135 let legacyAPISupported = resolvedValues[2]; 195 let legacyAPISupported = resolvedValues[2];
(...skipping 17 matching lines...) Expand all
153 }); 213 });
154 }); 214 });
155 } 215 }
156 216
157 port.on("safari.contentBlockingActive", (msg, sender) => 217 port.on("safari.contentBlockingActive", (msg, sender) =>
158 { 218 {
159 if (!contentBlockingActive && afterContentBlockingFinished) 219 if (!contentBlockingActive && afterContentBlockingFinished)
160 return afterContentBlockingFinished; 220 return afterContentBlockingFinished;
161 return contentBlockingActive; 221 return contentBlockingActive;
162 }); 222 });
OLDNEW
« dependencies ('K') | « dependencies ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld