LEFT | RIGHT |
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 |
(...skipping 13 matching lines...) Expand all Loading... |
24 let MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; | 24 let MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; |
25 let MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; | 25 let MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; |
26 let MILLIS_IN_HOUR = exports.MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; | 26 let MILLIS_IN_HOUR = exports.MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; |
27 let MILLIS_IN_DAY = exports.MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; | 27 let MILLIS_IN_DAY = exports.MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; |
28 | 28 |
29 /** | 29 /** |
30 * Creates a new downloader instance. | 30 * Creates a new downloader instance. |
31 * @param {Function} dataSource Function that will yield downloadable objects o
n each check | 31 * @param {Function} dataSource Function that will yield downloadable objects o
n each check |
32 * @param {Integer} initialDelay Number of milliseconds to wait before the firs
t check | 32 * @param {Integer} initialDelay Number of milliseconds to wait before the firs
t check |
33 * @param {Integer} checkInterval Interval between the checks | 33 * @param {Integer} checkInterval Interval between the checks |
34 * @param {function} downloadCallback optional function that's being called when
something needs to be downloaded | |
35 * @constructor | 34 * @constructor |
36 */ | 35 */ |
37 let Downloader = exports.Downloader = function Downloader(dataSource, initialDel
ay, checkInterval, downloadCallback) | 36 let Downloader = exports.Downloader = function Downloader(dataSource, initialDel
ay, checkInterval) |
38 { | 37 { |
39 this.dataSource = dataSource; | 38 this.dataSource = dataSource; |
40 this.downloadCallback = downloadCallback || this._download; | |
41 this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); | 39 this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
42 this._timer.initWithCallback(function() | 40 this._timer.initWithCallback(function() |
43 { | 41 { |
44 this._timer.delay = checkInterval; | 42 this._timer.delay = checkInterval; |
45 this._doCheck(); | 43 this._doCheck(); |
46 }.bind(this), initialDelay, Ci.nsITimer.TYPE_REPEATING_SLACK); | 44 }.bind(this), initialDelay, Ci.nsITimer.TYPE_REPEATING_SLACK); |
47 this._downloading = Object.create(null); | 45 this._downloading = Object.create(null); |
48 } | 46 } |
49 Downloader.prototype = | 47 Downloader.prototype = |
50 { | 48 { |
51 /** | 49 /** |
52 * Timer triggering the downloads. | 50 * Timer triggering the downloads. |
53 * @type nsITimer | 51 * @type nsITimer |
54 */ | 52 */ |
55 _timer: null, | 53 _timer: null, |
56 | 54 |
57 /** | 55 /** |
58 * Map containing the URLs of objects currently being downloaded as its keys. | 56 * Map containing the URLs of objects currently being downloaded as its keys. |
59 */ | 57 */ |
60 _downloading: null, | 58 _downloading: null, |
61 | 59 |
62 /** | 60 /** |
63 * Function that will yield downloadable objects on each check. | 61 * Function that will yield downloadable objects on each check. |
64 * @type Function | 62 * @type Function |
65 */ | 63 */ |
66 dataSource: null, | 64 dataSource: null, |
67 | 65 |
68 /** | 66 /** |
69 * Function that's being called when something needs to be downloaded. | |
70 * @type Function | |
71 */ | |
72 downloadCallback: null, | |
73 | |
74 /** | |
75 * Maximal time interval that the checks can be left out until the soft | 67 * Maximal time interval that the checks can be left out until the soft |
76 * expiration interval increases. | 68 * expiration interval increases. |
77 * @type Integer | 69 * @type Integer |
78 */ | 70 */ |
79 maxAbsenceInterval: 1 * MILLIS_IN_DAY, | 71 maxAbsenceInterval: 1 * MILLIS_IN_DAY, |
80 | 72 |
81 /** | 73 /** |
82 * Minimal time interval before retrying a download after an error. | 74 * Minimal time interval before retrying a download after an error. |
83 * @type Integer | 75 * @type Integer |
84 */ | 76 */ |
(...skipping 29 matching lines...) Expand all Loading... |
114 * callback can return an error code to indicate that the data is wrong. | 106 * callback can return an error code to indicate that the data is wrong. |
115 * @type Function | 107 * @type Function |
116 */ | 108 */ |
117 onDownloadSuccess: null, | 109 onDownloadSuccess: null, |
118 | 110 |
119 /** | 111 /** |
120 * Callback to be triggered whenever a download fails. | 112 * Callback to be triggered whenever a download fails. |
121 * @type Function | 113 * @type Function |
122 */ | 114 */ |
123 onDownloadError: null, | 115 onDownloadError: null, |
| 116 |
| 117 /** |
| 118 * Callback to be triggered for POST request data generation. |
| 119 * @type Function |
| 120 */ |
| 121 generateRequestData: null, |
| 122 |
| 123 /** |
| 124 * List of valid responses. |
| 125 * @type Array |
| 126 */ |
| 127 validResponses: [200], |
124 | 128 |
125 /** | 129 /** |
126 * Checks whether anything needs downloading. | 130 * Checks whether anything needs downloading. |
127 */ | 131 */ |
128 _doCheck: function() | 132 _doCheck: function() |
129 { | 133 { |
130 let now = Date.now(); | 134 let now = Date.now(); |
131 for (let downloadable of this.dataSource()) | 135 for (let downloadable of this.dataSource()) |
132 { | 136 { |
133 if (downloadable.lastCheck && now - downloadable.lastCheck > this.maxAbsen
ceInterval) | 137 if (downloadable.lastCheck && now - downloadable.lastCheck > this.maxAbsen
ceInterval) |
(...skipping 17 matching lines...) Expand all Loading... |
151 this.onExpirationChange(downloadable); | 155 this.onExpirationChange(downloadable); |
152 | 156 |
153 // Does that object need downloading? | 157 // Does that object need downloading? |
154 if (downloadable.softExpiration > now && downloadable.hardExpiration > now
) | 158 if (downloadable.softExpiration > now && downloadable.hardExpiration > now
) |
155 continue; | 159 continue; |
156 | 160 |
157 // Do not retry downloads too often | 161 // Do not retry downloads too often |
158 if (downloadable.lastError && now - downloadable.lastError < this.minRetry
Interval) | 162 if (downloadable.lastError && now - downloadable.lastError < this.minRetry
Interval) |
159 continue; | 163 continue; |
160 | 164 |
161 this.downloadCallback(downloadable, 0); | 165 this._download(downloadable, 0); |
162 } | 166 } |
163 }, | 167 }, |
164 | 168 |
165 /** | 169 /** |
166 * Stops the periodic checks. | 170 * Stops the periodic checks. |
167 */ | 171 */ |
168 cancel: function() | 172 cancel: function() |
169 { | 173 { |
170 this._timer.cancel(); | 174 this._timer.cancel(); |
171 }, | 175 }, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 } | 255 } |
252 | 256 |
253 this.onDownloadError(downloadable, downloadUrl, error, channelStatus, re
sponseStatus, redirectCallback); | 257 this.onDownloadError(downloadable, downloadUrl, error, channelStatus, re
sponseStatus, redirectCallback); |
254 } | 258 } |
255 }.bind(this); | 259 }.bind(this); |
256 | 260 |
257 try | 261 try |
258 { | 262 { |
259 request = new XMLHttpRequest(); | 263 request = new XMLHttpRequest(); |
260 request.mozBackgroundRequest = true; | 264 request.mozBackgroundRequest = true; |
261 request.open("GET", downloadUrl); | 265 request.open(this.generateRequestData ? "POST" : "GET", downloadUrl); |
262 } | 266 } |
263 catch (e) | 267 catch (e) |
264 { | 268 { |
265 errorCallback("synchronize_invalid_url"); | 269 errorCallback("synchronize_invalid_url"); |
266 return; | 270 return; |
267 } | 271 } |
268 | 272 |
269 try { | 273 try { |
270 request.overrideMimeType("text/plain"); | 274 request.overrideMimeType("text/plain"); |
271 request.channel.loadFlags = request.channel.loadFlags | | 275 request.channel.loadFlags = request.channel.loadFlags | |
(...skipping 19 matching lines...) Expand all Loading... |
291 }.bind(this), false); | 295 }.bind(this), false); |
292 | 296 |
293 request.addEventListener("load", function(event) | 297 request.addEventListener("load", function(event) |
294 { | 298 { |
295 if (onShutdown.done) | 299 if (onShutdown.done) |
296 return; | 300 return; |
297 | 301 |
298 delete this._downloading[downloadable.url]; | 302 delete this._downloading[downloadable.url]; |
299 | 303 |
300 // Status will be 0 for non-HTTP requests | 304 // Status will be 0 for non-HTTP requests |
301 if (request.status && request.status != 200) | 305 if (request.status && this.validResponses.indexOf(request.status) == -1) |
302 { | 306 { |
303 errorCallback("synchronize_connection_error"); | 307 errorCallback("synchronize_connection_error"); |
304 return; | 308 return; |
305 } | 309 } |
306 | 310 |
307 downloadable.downloadCount++; | 311 downloadable.downloadCount++; |
308 | 312 |
309 this.onDownloadSuccess(downloadable, request.responseText, errorCallback,
function redirectCallback(url) | 313 this.onDownloadSuccess(downloadable, request.responseText, errorCallback,
function redirectCallback(url) |
310 { | 314 { |
311 if (redirects >= this.maxRedirects) | 315 if (redirects >= this.maxRedirects) |
312 errorCallback("synchronize_connection_error"); | 316 errorCallback("synchronize_connection_error"); |
313 else | 317 else |
314 { | 318 { |
315 downloadable.redirectURL = url; | 319 downloadable.redirectURL = url; |
316 this._download(downloadable, redirects + 1); | 320 this._download(downloadable, redirects + 1); |
317 } | 321 } |
318 }.bind(this)); | 322 }.bind(this)); |
319 }.bind(this), false); | 323 }.bind(this), false); |
320 | 324 |
321 request.send(null); | 325 if (this.generateRequestData) |
| 326 { |
| 327 Promise.resolve(this.generateRequestData(downloadable)) |
| 328 .then(data => { |
| 329 request.setRequestHeader("Content-Type", "application/json"); |
| 330 request.send(JSON.stringify(data)); |
| 331 }); |
| 332 } |
| 333 else |
| 334 request.send(null); |
322 | 335 |
323 this._downloading[downloadable.url] = true; | 336 this._downloading[downloadable.url] = true; |
324 if (this.onDownloadStarted) | 337 if (this.onDownloadStarted) |
325 this.onDownloadStarted(downloadable); | 338 this.onDownloadStarted(downloadable); |
326 }, | 339 }, |
327 | 340 |
328 /** | 341 /** |
329 * Produces a soft and a hard expiration interval for a given supplied | 342 * Produces a soft and a hard expiration interval for a given supplied |
330 * expiration interval. | 343 * expiration interval. |
331 * @return {Array} soft and hard expiration interval | 344 * @return {Array} soft and hard expiration interval |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 * @type Integer | 406 * @type Integer |
394 */ | 407 */ |
395 hardExpiration: 0, | 408 hardExpiration: 0, |
396 | 409 |
397 /** | 410 /** |
398 * Number indicating how often the object was downloaded. | 411 * Number indicating how often the object was downloaded. |
399 * @type Integer | 412 * @type Integer |
400 */ | 413 */ |
401 downloadCount: 0, | 414 downloadCount: 0, |
402 }; | 415 }; |
LEFT | RIGHT |