| OLD | NEW | 
|    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 | 
|   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 "use strict"; | 
 |   19  | 
|   18 /** |   20 /** | 
|   19  * @fileOverview Downloads a set of URLs in regular time intervals. |   21  * @fileOverview Downloads a set of URLs in regular time intervals. | 
|   20  */ |   22  */ | 
|   21  |   23  | 
|   22 let {Utils} = require("utils"); |   24 const {Utils} = require("utils"); | 
|   23  |   25  | 
|   24 let MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; |   26 let MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; | 
|   25 let MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; |   27 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; |   28 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; |   29 let MILLIS_IN_DAY = exports.MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; | 
|   28  |   30  | 
 |   31 let Downloader = | 
|   29 /** |   32 /** | 
|   30  * Creates a new downloader instance. |   33  * Creates a new downloader instance. | 
|   31  * @param {Function} dataSource  Function that will yield downloadable objects o
     n each check |   34  * @param {Function} dataSource  Function that will yield downloadable objects | 
|   32  * @param {Integer} initialDelay  Number of milliseconds to wait before the firs
     t check |   35  *                               on each check | 
|   33  * @param {Integer} checkInterval  Interval between the checks |   36  * @param {number} initialDelay  Number of milliseconds to wait before the | 
 |   37  *                                 first check | 
 |   38  * @param {number} checkInterval  Interval between the checks | 
|   34  * @constructor |   39  * @constructor | 
|   35  */ |   40  */ | 
|   36 let Downloader = exports.Downloader = function Downloader(dataSource, initialDel
     ay, checkInterval) |   41 exports.Downloader = function(dataSource, initialDelay, checkInterval) | 
|   37 { |   42 { | 
|   38   this.dataSource = dataSource; |   43   this.dataSource = dataSource; | 
|   39   this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |   44   this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); | 
|   40   this._timer.initWithCallback(function() |   45   this._timer.initWithCallback(() => | 
|   41   { |   46   { | 
|   42     this._timer.delay = checkInterval; |   47     this._timer.delay = checkInterval; | 
|   43     this._doCheck(); |   48     this._doCheck(); | 
|   44   }.bind(this), initialDelay, Ci.nsITimer.TYPE_REPEATING_SLACK); |   49   }, initialDelay, Ci.nsITimer.TYPE_REPEATING_SLACK); | 
|   45   this._downloading = Object.create(null); |   50   this._downloading = Object.create(null); | 
|   46 } |   51 }; | 
|   47 Downloader.prototype = |   52 Downloader.prototype = | 
|   48 { |   53 { | 
|   49   /** |   54   /** | 
|   50    * Timer triggering the downloads. |   55    * Timer triggering the downloads. | 
|   51    * @type nsITimer |   56    * @type {nsITimer} | 
|   52    */ |   57    */ | 
|   53   _timer: null, |   58   _timer: null, | 
|   54  |   59  | 
|   55   /** |   60   /** | 
|   56    * Map containing the URLs of objects currently being downloaded as its keys. |   61    * Map containing the URLs of objects currently being downloaded as its keys. | 
|   57    */ |   62    */ | 
|   58   _downloading: null, |   63   _downloading: null, | 
|   59  |   64  | 
|   60   /** |   65   /** | 
|   61    * Function that will yield downloadable objects on each check. |   66    * Function that will yield downloadable objects on each check. | 
|   62    * @type Function |   67    * @type {Function} | 
|   63    */ |   68    */ | 
|   64   dataSource: null, |   69   dataSource: null, | 
|   65  |   70  | 
|   66   /** |   71   /** | 
|   67    * Maximal time interval that the checks can be left out until the soft |   72    * Maximal time interval that the checks can be left out until the soft | 
|   68    * expiration interval increases. |   73    * expiration interval increases. | 
|   69    * @type Integer |   74    * @type {number} | 
|   70    */ |   75    */ | 
|   71   maxAbsenceInterval: 1 * MILLIS_IN_DAY, |   76   maxAbsenceInterval: 1 * MILLIS_IN_DAY, | 
|   72  |   77  | 
|   73   /** |   78   /** | 
|   74    * Minimal time interval before retrying a download after an error. |   79    * Minimal time interval before retrying a download after an error. | 
|   75    * @type Integer |   80    * @type {number} | 
|   76    */ |   81    */ | 
|   77   minRetryInterval: 1 * MILLIS_IN_DAY, |   82   minRetryInterval: 1 * MILLIS_IN_DAY, | 
|   78  |   83  | 
|   79   /** |   84   /** | 
|   80    * Maximal allowed expiration interval, larger expiration intervals will be |   85    * Maximal allowed expiration interval, larger expiration intervals will be | 
|   81    * corrected. |   86    * corrected. | 
|   82    * @type Integer |   87    * @type {number} | 
|   83    */ |   88    */ | 
|   84   maxExpirationInterval: 14 * MILLIS_IN_DAY, |   89   maxExpirationInterval: 14 * MILLIS_IN_DAY, | 
|   85  |   90  | 
|   86   /** |   91   /** | 
|   87    * Maximal number of redirects before the download is considered as failed. |   92    * Maximal number of redirects before the download is considered as failed. | 
|   88    * @type Integer |   93    * @type {number} | 
|   89    */ |   94    */ | 
|   90   maxRedirects: 5, |   95   maxRedirects: 5, | 
|   91  |   96  | 
|   92   /** |   97   /** | 
|   93    * Called whenever expiration intervals for an object need to be adapted. |   98    * Called whenever expiration intervals for an object need to be adapted. | 
|   94    * @type Function |   99    * @type {Function} | 
|   95    */ |  100    */ | 
|   96   onExpirationChange: null, |  101   onExpirationChange: null, | 
|   97  |  102  | 
|   98   /** |  103   /** | 
|   99    * Callback to be triggered whenever a download starts. |  104    * Callback to be triggered whenever a download starts. | 
|  100    * @type Function |  105    * @type {Function} | 
|  101    */ |  106    */ | 
|  102   onDownloadStarted: null, |  107   onDownloadStarted: null, | 
|  103  |  108  | 
|  104   /** |  109   /** | 
|  105    * Callback to be triggered whenever a download finishes successfully. The |  110    * Callback to be triggered whenever a download finishes successfully. The | 
|  106    * callback can return an error code to indicate that the data is wrong. |  111    * callback can return an error code to indicate that the data is wrong. | 
|  107    * @type Function |  112    * @type {Function} | 
|  108    */ |  113    */ | 
|  109   onDownloadSuccess: null, |  114   onDownloadSuccess: null, | 
|  110  |  115  | 
|  111   /** |  116   /** | 
|  112    * Callback to be triggered whenever a download fails. |  117    * Callback to be triggered whenever a download fails. | 
|  113    * @type Function |  118    * @type {Function} | 
|  114    */ |  119    */ | 
|  115   onDownloadError: null, |  120   onDownloadError: null, | 
|  116  |  121  | 
|  117   /** |  122   /** | 
|  118    * Checks whether anything needs downloading. |  123    * Checks whether anything needs downloading. | 
|  119    */ |  124    */ | 
|  120   _doCheck: function() |  125   _doCheck() | 
|  121   { |  126   { | 
|  122     let now = Date.now(); |  127     let now = Date.now(); | 
|  123     for (let downloadable of this.dataSource()) |  128     for (let downloadable of this.dataSource()) | 
|  124     { |  129     { | 
|  125       if (downloadable.lastCheck && now - downloadable.lastCheck > this.maxAbsen
     ceInterval) |  130       if (downloadable.lastCheck && | 
 |  131           now - downloadable.lastCheck > this.maxAbsenceInterval) | 
|  126       { |  132       { | 
|  127         // No checks for a long time interval - user must have been offline, e.g
     . |  133         // No checks for a long time interval - user must have been | 
|  128         // during a weekend. Increase soft expiration to prevent load peaks on t
     he |  134         // offline, e.g.  during a weekend. Increase soft expiration | 
|  129         // server. |  135         // to prevent load peaks on the server. | 
|  130         downloadable.softExpiration += now - downloadable.lastCheck; |  136         downloadable.softExpiration += now - downloadable.lastCheck; | 
|  131       } |  137       } | 
|  132       downloadable.lastCheck = now; |  138       downloadable.lastCheck = now; | 
|  133  |  139  | 
|  134       // Sanity check: do expiration times make sense? Make sure people changing |  140       // Sanity check: do expiration times make sense? Make sure people changing | 
|  135       // system clock don't get stuck with outdated subscriptions. |  141       // system clock don't get stuck with outdated subscriptions. | 
|  136       if (downloadable.hardExpiration - now > this.maxExpirationInterval) |  142       if (downloadable.hardExpiration - now > this.maxExpirationInterval) | 
|  137         downloadable.hardExpiration = now + this.maxExpirationInterval; |  143         downloadable.hardExpiration = now + this.maxExpirationInterval; | 
|  138       if (downloadable.softExpiration - now > this.maxExpirationInterval) |  144       if (downloadable.softExpiration - now > this.maxExpirationInterval) | 
|  139         downloadable.softExpiration = now + this.maxExpirationInterval; |  145         downloadable.softExpiration = now + this.maxExpirationInterval; | 
|  140  |  146  | 
|  141       // Notify the caller about changes to expiration parameters |  147       // Notify the caller about changes to expiration parameters | 
|  142       if (this.onExpirationChange) |  148       if (this.onExpirationChange) | 
|  143         this.onExpirationChange(downloadable); |  149         this.onExpirationChange(downloadable); | 
|  144  |  150  | 
|  145       // Does that object need downloading? |  151       // Does that object need downloading? | 
|  146       if (downloadable.softExpiration > now && downloadable.hardExpiration > now
     ) |  152       if (downloadable.softExpiration > now && | 
 |  153           downloadable.hardExpiration > now) | 
|  147         continue; |  154         continue; | 
|  148  |  155  | 
|  149       // Do not retry downloads too often |  156       // Do not retry downloads too often | 
|  150       if (downloadable.lastError && now - downloadable.lastError < this.minRetry
     Interval) |  157       if (downloadable.lastError && | 
 |  158           now - downloadable.lastError < this.minRetryInterval) | 
|  151         continue; |  159         continue; | 
|  152  |  160  | 
|  153       this._download(downloadable, 0); |  161       this._download(downloadable, 0); | 
|  154     } |  162     } | 
|  155   }, |  163   }, | 
|  156  |  164  | 
|  157   /** |  165   /** | 
|  158    * Stops the periodic checks. |  166    * Stops the periodic checks. | 
|  159    */ |  167    */ | 
|  160   cancel: function() |  168   cancel() | 
|  161   { |  169   { | 
|  162     this._timer.cancel(); |  170     this._timer.cancel(); | 
|  163   }, |  171   }, | 
|  164  |  172  | 
|  165   /** |  173   /** | 
|  166    * Checks whether an address is currently being downloaded. |  174    * Checks whether an address is currently being downloaded. | 
 |  175    * @param {string} url | 
 |  176    * @return {boolean} | 
|  167    */ |  177    */ | 
|  168   isDownloading: function(/**String*/ url) /**Boolean*/ |  178   isDownloading(url) | 
|  169   { |  179   { | 
|  170     return url in this._downloading; |  180     return url in this._downloading; | 
|  171   }, |  181   }, | 
|  172  |  182  | 
|  173   /** |  183   /** | 
|  174    * Starts downloading for an object. |  184    * Starts downloading for an object. | 
 |  185    * @param {Downloadable} downloadable | 
|  175    */ |  186    */ | 
|  176   download: function(/**Downloadable*/ downloadable) |  187   download(downloadable) | 
|  177   { |  188   { | 
|  178     // Make sure to detach download from the current execution context |  189     // Make sure to detach download from the current execution context | 
|  179     Utils.runAsync(this._download.bind(this, downloadable, 0)); |  190     Utils.runAsync(this._download.bind(this, downloadable, 0)); | 
|  180   }, |  191   }, | 
|  181  |  192  | 
|  182   /** |  193   /** | 
|  183    * Generates the real download URL for an object by appending various |  194    * Generates the real download URL for an object by appending various | 
|  184    * parameters. |  195    * parameters. | 
 |  196    * @param {Downloadable} downloadable | 
 |  197    * @return {string} | 
|  185    */ |  198    */ | 
|  186   getDownloadUrl: function(/**Downloadable*/ downloadable)  /** String*/ |  199   getDownloadUrl(downloadable) | 
|  187   { |  200   { | 
|  188     let {addonName, addonVersion, application, applicationVersion, platform, pla
     tformVersion} = require("info"); |  201     const {addonName, addonVersion, application, applicationVersion, | 
 |  202            platform, platformVersion} = require("info"); | 
|  189     let url = downloadable.redirectURL || downloadable.url; |  203     let url = downloadable.redirectURL || downloadable.url; | 
|  190     if (url.indexOf("?") >= 0) |  204     if (url.indexOf("?") >= 0) | 
|  191       url += "&"; |  205       url += "&"; | 
|  192     else |  206     else | 
|  193       url += "?"; |  207       url += "?"; | 
|  194     // We limit the download count to 4+ to keep the request anonymized |  208     // We limit the download count to 4+ to keep the request anonymized | 
|  195     let downloadCount = downloadable.downloadCount; |  209     let {downloadCount} = downloadable; | 
|  196     if (downloadCount > 4) |  210     if (downloadCount > 4) | 
|  197       downloadCount = "4+"; |  211       downloadCount = "4+"; | 
|  198     url += "addonName=" + encodeURIComponent(addonName) + |  212     url += "addonName=" + encodeURIComponent(addonName) + | 
|  199         "&addonVersion=" + encodeURIComponent(addonVersion) + |  213         "&addonVersion=" + encodeURIComponent(addonVersion) + | 
|  200         "&application=" + encodeURIComponent(application) + |  214         "&application=" + encodeURIComponent(application) + | 
|  201         "&applicationVersion=" + encodeURIComponent(applicationVersion) + |  215         "&applicationVersion=" + encodeURIComponent(applicationVersion) + | 
|  202         "&platform=" + encodeURIComponent(platform) + |  216         "&platform=" + encodeURIComponent(platform) + | 
|  203         "&platformVersion=" + encodeURIComponent(platformVersion) + |  217         "&platformVersion=" + encodeURIComponent(platformVersion) + | 
|  204         "&lastVersion=" + encodeURIComponent(downloadable.lastVersion) + |  218         "&lastVersion=" + encodeURIComponent(downloadable.lastVersion) + | 
|  205         "&downloadCount=" + encodeURIComponent(downloadCount); |  219         "&downloadCount=" + encodeURIComponent(downloadCount); | 
|  206     return url; |  220     return url; | 
|  207   }, |  221   }, | 
|  208  |  222  | 
|  209   _download: function(downloadable, redirects) |  223   _download(downloadable, redirects) | 
|  210   { |  224   { | 
|  211     if (this.isDownloading(downloadable.url)) |  225     if (this.isDownloading(downloadable.url)) | 
|  212       return; |  226       return; | 
|  213  |  227  | 
|  214     let downloadUrl = this.getDownloadUrl(downloadable); |  228     let downloadUrl = this.getDownloadUrl(downloadable); | 
|  215     let request = null; |  229     let request = null; | 
|  216  |  230  | 
|  217     let errorCallback = function errorCallback(error) |  231     let errorCallback = function errorCallback(error) | 
|  218     { |  232     { | 
|  219       let channelStatus = -1; |  233       let channelStatus = -1; | 
|  220       try |  234       try | 
|  221       { |  235       { | 
|  222         channelStatus = request.channel.status; |  236         channelStatus = request.channel.status; | 
|  223       } catch (e) {} |  237       } | 
 |  238       catch (e) {} | 
|  224  |  239  | 
|  225       let responseStatus = request.status; |  240       let responseStatus = request.status; | 
|  226  |  241  | 
|  227       Cu.reportError("Adblock Plus: Downloading URL " + downloadable.url + " fai
     led (" + error + ")\n" + |  242       Cu.reportError("Adblock Plus: Downloading URL " + downloadable.url + | 
 |  243                      " failed (" + error + ")\n" + | 
|  228                      "Download address: " + downloadUrl + "\n" + |  244                      "Download address: " + downloadUrl + "\n" + | 
|  229                      "Channel status: " + channelStatus + "\n" + |  245                      "Channel status: " + channelStatus + "\n" + | 
|  230                      "Server response: " + responseStatus); |  246                      "Server response: " + responseStatus); | 
|  231  |  247  | 
|  232       if (this.onDownloadError) |  248       if (this.onDownloadError) | 
|  233       { |  249       { | 
|  234         // Allow one extra redirect if the error handler gives us a redirect URL |  250         // Allow one extra redirect if the error handler gives us a redirect URL | 
|  235         let redirectCallback = null; |  251         let redirectCallback = null; | 
|  236         if (redirects <= this.maxRedirects) |  252         if (redirects <= this.maxRedirects) | 
|  237         { |  253         { | 
|  238           redirectCallback = function redirectCallback(url) |  254           redirectCallback = (url) => | 
|  239           { |  255           { | 
|  240             downloadable.redirectURL = url; |  256             downloadable.redirectURL = url; | 
|  241             this._download(downloadable, redirects + 1); |  257             this._download(downloadable, redirects + 1); | 
|  242           }.bind(this); |  258           }; | 
|  243         } |  259         } | 
|  244  |  260  | 
|  245         this.onDownloadError(downloadable, downloadUrl, error, channelStatus, re
     sponseStatus, redirectCallback); |  261         this.onDownloadError(downloadable, downloadUrl, error, channelStatus, | 
 |  262                              responseStatus, redirectCallback); | 
|  246       } |  263       } | 
|  247     }.bind(this); |  264     }.bind(this); | 
|  248  |  265  | 
|  249     try |  266     try | 
|  250     { |  267     { | 
|  251       request = new XMLHttpRequest(); |  268       request = new XMLHttpRequest(); | 
|  252       request.mozBackgroundRequest = true; |  269       request.mozBackgroundRequest = true; | 
|  253       request.open("GET", downloadUrl); |  270       request.open("GET", downloadUrl); | 
|  254     } |  271     } | 
|  255     catch (e) |  272     catch (e) | 
|  256     { |  273     { | 
|  257       errorCallback("synchronize_invalid_url"); |  274       errorCallback("synchronize_invalid_url"); | 
|  258       return; |  275       return; | 
|  259     } |  276     } | 
|  260  |  277  | 
|  261     try { |  278     try | 
 |  279     { | 
|  262       request.overrideMimeType("text/plain"); |  280       request.overrideMimeType("text/plain"); | 
|  263       request.channel.loadFlags = request.channel.loadFlags | |  281       request.channel.loadFlags = request.channel.loadFlags | | 
|  264                                   request.channel.INHIBIT_CACHING | |  282                                   request.channel.INHIBIT_CACHING | | 
|  265                                   request.channel.VALIDATE_ALWAYS; |  283                                   request.channel.VALIDATE_ALWAYS; | 
|  266  |  284  | 
|  267       // Override redirect limit from preferences, user might have set it to 1 |  285       // Override redirect limit from preferences, user might have set it to 1 | 
|  268       if (request.channel instanceof Ci.nsIHttpChannel) |  286       if (request.channel instanceof Ci.nsIHttpChannel) | 
|  269         request.channel.redirectionLimit = this.maxRedirects; |  287         request.channel.redirectionLimit = this.maxRedirects; | 
|  270     } |  288     } | 
|  271     catch (e) |  289     catch (e) | 
|  272     { |  290     { | 
|  273       Cu.reportError(e) |  291       Cu.reportError(e); | 
|  274     } |  292     } | 
|  275  |  293  | 
|  276     request.addEventListener("error", function(event) |  294     request.addEventListener("error", event => | 
|  277     { |  295     { | 
|  278       if (onShutdown.done) |  296       if (onShutdown.done) | 
|  279         return; |  297         return; | 
|  280  |  298  | 
|  281       delete this._downloading[downloadable.url]; |  299       delete this._downloading[downloadable.url]; | 
|  282       errorCallback("synchronize_connection_error"); |  300       errorCallback("synchronize_connection_error"); | 
|  283     }.bind(this), false); |  301     }, false); | 
|  284  |  302  | 
|  285     request.addEventListener("load", function(event) |  303     request.addEventListener("load", event => | 
|  286     { |  304     { | 
|  287       if (onShutdown.done) |  305       if (onShutdown.done) | 
|  288         return; |  306         return; | 
|  289  |  307  | 
|  290       delete this._downloading[downloadable.url]; |  308       delete this._downloading[downloadable.url]; | 
|  291  |  309  | 
|  292       // Status will be 0 for non-HTTP requests |  310       // Status will be 0 for non-HTTP requests | 
|  293       if (request.status && request.status != 200) |  311       if (request.status && request.status != 200) | 
|  294       { |  312       { | 
|  295         errorCallback("synchronize_connection_error"); |  313         errorCallback("synchronize_connection_error"); | 
|  296         return; |  314         return; | 
|  297       } |  315       } | 
|  298  |  316  | 
|  299       downloadable.downloadCount++; |  317       downloadable.downloadCount++; | 
|  300  |  318  | 
|  301       this.onDownloadSuccess(downloadable, request.responseText, errorCallback, 
     function redirectCallback(url) |  319       this.onDownloadSuccess( | 
|  302       { |  320         downloadable, request.responseText, errorCallback, | 
|  303         if (redirects >= this.maxRedirects) |  321         url => | 
|  304           errorCallback("synchronize_connection_error"); |  | 
|  305         else |  | 
|  306         { |  322         { | 
|  307           downloadable.redirectURL = url; |  323           if (redirects >= this.maxRedirects) | 
|  308           this._download(downloadable, redirects + 1); |  324             errorCallback("synchronize_connection_error"); | 
 |  325           else | 
 |  326           { | 
 |  327             downloadable.redirectURL = url; | 
 |  328             this._download(downloadable, redirects + 1); | 
 |  329           } | 
|  309         } |  330         } | 
|  310       }.bind(this)); |  331       ); | 
|  311     }.bind(this), false); |  332     }); | 
|  312  |  333  | 
|  313     request.send(null); |  334     request.send(null); | 
|  314  |  335  | 
|  315     this._downloading[downloadable.url] = true; |  336     this._downloading[downloadable.url] = true; | 
|  316     if (this.onDownloadStarted) |  337     if (this.onDownloadStarted) | 
|  317       this.onDownloadStarted(downloadable); |  338       this.onDownloadStarted(downloadable); | 
|  318   }, |  339   }, | 
|  319  |  340  | 
|  320   /** |  341   /** | 
|  321    * 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 | 
|  322    * expiration interval. |  343    * expiration interval. | 
 |  344    * @param {number} interval | 
|  323    * @return {Array} soft and hard expiration interval |  345    * @return {Array} soft and hard expiration interval | 
|  324    */ |  346    */ | 
|  325   processExpirationInterval: function(/**Integer*/ interval) |  347   processExpirationInterval(interval) | 
|  326   { |  348   { | 
|  327     interval = Math.min(Math.max(interval, 0), this.maxExpirationInterval); |  349     interval = Math.min(Math.max(interval, 0), this.maxExpirationInterval); | 
|  328     let soft = Math.round(interval * (Math.random() * 0.4 + 0.8)); |  350     let soft = Math.round(interval * (Math.random() * 0.4 + 0.8)); | 
|  329     let hard = interval * 2; |  351     let hard = interval * 2; | 
|  330     let now = Date.now(); |  352     let now = Date.now(); | 
|  331     return [now + soft, now + hard]; |  353     return [now + soft, now + hard]; | 
|  332   } |  354   } | 
|  333 }; |  355 }; | 
|  334  |  356  | 
|  335 /** |  357 /** | 
|  336  * An object that can be downloaded by the downloadable |  358  * An object that can be downloaded by the downloadable | 
|  337  * @param {String} url  URL that has to be requested for the object |  359  * @param {string} url  URL that has to be requested for the object | 
|  338  * @constructor |  360  * @constructor | 
|  339  */ |  361  */ | 
|  340 let Downloadable = exports.Downloadable = function Downloadable(url) |  362 let Downloadable = exports.Downloadable = function Downloadable(url) | 
|  341 { |  363 { | 
|  342   this.url = url; |  364   this.url = url; | 
|  343 } |  365 }; | 
|  344 Downloadable.prototype = |  366 Downloadable.prototype = | 
|  345 { |  367 { | 
|  346   /** |  368   /** | 
|  347    * URL that has to be requested for the object. |  369    * URL that has to be requested for the object. | 
|  348    * @type String |  370    * @type {string} | 
|  349    */ |  371    */ | 
|  350   url: null, |  372   url: null, | 
|  351  |  373  | 
|  352   /** |  374   /** | 
|  353    * URL that the download was redirected to if any. |  375    * URL that the download was redirected to if any. | 
|  354    * @type String |  376    * @type {string} | 
|  355    */ |  377    */ | 
|  356   redirectURL: null, |  378   redirectURL: null, | 
|  357  |  379  | 
|  358   /** |  380   /** | 
|  359    * Time of last download error or 0 if the last download was successful. |  381    * Time of last download error or 0 if the last download was successful. | 
|  360    * @type Integer |  382    * @type {number} | 
|  361    */ |  383    */ | 
|  362   lastError: 0, |  384   lastError: 0, | 
|  363  |  385  | 
|  364   /** |  386   /** | 
|  365    * Time of last check whether the object needs downloading. |  387    * Time of last check whether the object needs downloading. | 
|  366    * @type Integer |  388    * @type {number} | 
|  367    */ |  389    */ | 
|  368   lastCheck: 0, |  390   lastCheck: 0, | 
|  369  |  391  | 
|  370   /** |  392   /** | 
|  371    * Object version corresponding to the last successful download. |  393    * Object version corresponding to the last successful download. | 
|  372    * @type Integer |  394    * @type {number} | 
|  373    */ |  395    */ | 
|  374   lastVersion: 0, |  396   lastVersion: 0, | 
|  375  |  397  | 
|  376   /** |  398   /** | 
|  377    * Soft expiration interval, will increase if no checks are performed for a |  399    * Soft expiration interval, will increase if no checks are performed for a | 
|  378    * while. |  400    * while. | 
|  379    * @type Integer |  401    * @type {number} | 
|  380    */ |  402    */ | 
|  381   softExpiration: 0, |  403   softExpiration: 0, | 
|  382  |  404  | 
|  383   /** |  405   /** | 
|  384    * Hard expiration interval, this is fixed. |  406    * Hard expiration interval, this is fixed. | 
|  385    * @type Integer |  407    * @type {number} | 
|  386    */ |  408    */ | 
|  387   hardExpiration: 0, |  409   hardExpiration: 0, | 
|  388    |  410  | 
|  389   /** |  411   /** | 
|  390    * Number indicating how often the object was downloaded. |  412    * Number indicating how often the object was downloaded. | 
|  391    * @type Integer |  413    * @type {number} | 
|  392    */ |  414    */ | 
|  393   downloadCount: 0, |  415   downloadCount: 0 | 
|  394 }; |  416 }; | 
| OLD | NEW |