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: Don't wrap setContentBlocker call into another promise Created Aug. 16, 2017, 11:33 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') | « lib/requestBlocker.js ('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) =>
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 =>
kzar 2017/08/21 12:30:12 Nit: Since this is a named function maybe just use
Manish Jethani 2017/08/21 14:17:04 Done.
62 } 59 {
60 lastSetContentBlockerError = error;
61 contentBlockListDirty = false;
63 62
64 let contentBlockerList = new ContentBlockerList(); 63 if (error instanceof 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 {
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 {
95 afterContentBlockingFinished = new Promise(resolve => 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)
96 { 122 {
97 setContentBlocker(error => 123 pendingContentBlockerUpdate = {
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
132 afterContentBlockingFinished = setContentBlocker().then(() =>
133 {
134 if (!contentBlockingActive)
98 { 135 {
99 if (error instanceof Error) 136 contentBlockingActive = true;
100 { 137 clearBlockCounters();
101 let suppressErrorMessage = false; 138 }
139 },
140 error =>
141 {
142 let suppressErrorMessage = false;
102 143
103 // If the content blocking API fails the first time it's used the 144 // If the content blocking API fails the first time it's used the
104 // legacy blocking API (if available) won't have been disabled. 145 // legacy blocking API (if available) won't have been disabled.
105 if (!contentBlockingActive && legacyAPISupported) 146 if (!contentBlockingActive && legacyAPISupported)
106 { 147 {
107 Prefs.safariContentBlocker = false; 148 Prefs.safariContentBlocker = false;
108 // If content blocking failed on startup and we're switching back to 149 // 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. 150 // the legacy API anyway we don't need to show an error message.
110 if (isStartup) 151 if (isStartup)
111 suppressErrorMessage = true; 152 suppressErrorMessage = true;
112 } 153 }
113 154
114 if (!suppressErrorMessage) 155 if (!suppressErrorMessage)
115 alert(error.message); 156 alert(error.message);
116 } 157 })
117 else if (!contentBlockingActive) 158 .then(() =>
118 { 159 {
119 contentBlockingActive = true; 160 afterContentBlockingFinished = null;
120 clearBlockCounters();
121 }
122 161
123 resolve(contentBlockingActive); 162 // If there's another update pending, execute it now.
124 afterContentBlockingFinished = null; 163 if (pendingContentBlockerUpdate)
125 }); 164 {
165 let {params, setDirty} = pendingContentBlockerUpdate;
166 pendingContentBlockerUpdate = null;
167
168 if (setDirty)
169 contentBlockListDirty = true;
170
171 updateContentBlocker.apply(null, params);
172 return afterContentBlockingFinished;
173 }
174
175 return contentBlockingActive;
126 }); 176 });
127 } 177 }
128 178
129 if (contentBlockingSupported) 179 if (contentBlockingSupported)
130 { 180 {
131 Promise.all([Prefs.untilLoaded, 181 Promise.all([Prefs.untilLoaded,
132 FilterNotifier.once("load"), 182 FilterNotifier.once("load"),
133 legacyAPISupported]).then(resolvedValues => 183 legacyAPISupported]).then(resolvedValues =>
134 { 184 {
135 let legacyAPISupported = resolvedValues[2]; 185 let legacyAPISupported = resolvedValues[2];
(...skipping 17 matching lines...) Expand all
153 }); 203 });
154 }); 204 });
155 } 205 }
156 206
157 port.on("safari.contentBlockingActive", (msg, sender) => 207 port.on("safari.contentBlockingActive", (msg, sender) =>
158 { 208 {
159 if (!contentBlockingActive && afterContentBlockingFinished) 209 if (!contentBlockingActive && afterContentBlockingFinished)
160 return afterContentBlockingFinished; 210 return afterContentBlockingFinished;
161 return contentBlockingActive; 211 return contentBlockingActive;
162 }); 212 });
OLDNEW
« dependencies ('K') | « lib/requestBlocker.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld