Bug 801855 - Check update download progress to prevent overly large update from being downloaded. r=rstrong. a=akeybl
authorBrian R. Bondy <netzen@gmail.com>
Fri, 19 Oct 2012 12:43:54 -0400
changeset 116911 fe0e5fdcaa529e5e3bbe5fac032559d9f62b2836
parent 116910 b5ccf294711a884e9fdcce1e48718a5b7d9dd593
child 116912 6c9fc008e25c71e72b4cd34108ba23146f9dc86d
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong, akeybl
bugs801855
milestone18.0a2
Bug 801855 - Check update download progress to prevent overly large update from being downloaded. r=rstrong. a=akeybl
toolkit/mozapps/update/content/updates.js
toolkit/mozapps/update/nsUpdateService.js
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -1549,16 +1549,17 @@ var gDownloadingPage = {
    *          Status code containing the reason for the cessation.
    */
   onStopRequest: function(request, context, status) {
     if (this._downloadProgress.mode != "normal")
       this._downloadProgress.mode = "normal";
 
     var u = gUpdates.update;
     switch (status) {
+    case CoR.NS_ERROR_CORRUPTED_CONTENT:
     case CoR.NS_ERROR_UNEXPECTED:
       if (u.selectedPatch.state == STATE_DOWNLOAD_FAILED &&
           (u.isCompleteUpdate || u.patchCount != 2)) {
         // Verification error of complete patch, informational text is held in
         // the update object.
         this.cleanUp();
         gUpdates.wiz.goTo("errors");
         break;
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -2998,19 +2998,23 @@ Downloader.prototype = {
    * the user's existing installation or a patch representing the difference
    * between the new version and the previous version.
    */
   isCompleteUpdate: null,
 
   /**
    * Cancels the active download.
    */
-  cancel: function Downloader_cancel() {
-    if (this._request && this._request instanceof Ci.nsIRequest)
-      this._request.cancel(Cr.NS_BINDING_ABORTED);
+  cancel: function Downloader_cancel(cancelError) {
+    if (cancelError === undefined) {
+      cancelError = Cr.NS_BINDING_ABORTED;
+    }
+    if (this._request && this._request instanceof Ci.nsIRequest) {
+      this._request.cancel(cancelError);
+    }
   },
 
   /**
    * Whether or not a patch has been downloaded and staged for installation.
    */
   get patchIsStaged() {
     var readState = readStatusFile(getUpdatesDir());
     // Note that if we decide to download and apply new updates after another
@@ -3281,16 +3285,36 @@ Downloader.prototype = {
    *          The current number of bytes transferred
    * @param   maxProgress
    *          The total number of bytes that must be transferred
    */
   onProgress: function Downloader_onProgress(request, context, progress,
                                              maxProgress) {
     LOG("Downloader:onProgress - progress: " + progress + "/" + maxProgress);
 
+    if (progress > this._patch.size) {
+      LOG("Downloader:onProgress - progress: " + progress +
+          " is higher than patch size: " + this._patch.size);
+      // It's important that we use a different code than
+      // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference
+      // between a hash error and a wrong download error.
+      this.cancel(Cr.NS_ERROR_UNEXPECTED);
+      return;
+    }
+
+    if (maxProgress != this._patch.size) {
+      LOG("Downloader:onProgress - maxProgress: " + maxProgress +
+          " is not equal to expectd patch size: " + this._patch.size);
+      // It's important that we use a different code than
+      // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference
+      // between a hash error and a wrong download error.
+      this.cancel(Cr.NS_ERROR_UNEXPECTED);
+      return;
+    }
+
     var listeners = this._listeners.concat();
     var listenerCount = listeners.length;
     for (var i = 0; i < listenerCount; ++i) {
       var listener = listeners[i];
       if (listener instanceof Ci.nsIProgressEventSink)
         listener.onProgress(request, context, progress, maxProgress);
     }
   },
@@ -3353,18 +3377,17 @@ Downloader.prototype = {
         writeVersionFile(getUpdatesDir(), this._update.appVersion);
         this._update.installDate = (new Date()).getTime();
         this._update.statusText = gUpdateBundle.GetStringFromName("installPending");
       }
       else {
         LOG("Downloader:onStopRequest - download verification failed");
         state = STATE_DOWNLOAD_FAILED;
 
-        // TODO: use more informative error code here
-        status = Cr.NS_ERROR_UNEXPECTED;
+        status = Cr.NS_ERROR_CORRUPTED_CONTENT;
 
         // Yes, this code is a string.
         const vfCode = "verification_failed";
         var message = getStatusTextFromCode(vfCode, vfCode);
         this._update.statusText = message;
 
         if (this._update.isCompleteUpdate || this._update.patchCount != 2)
           deleteActiveUpdate = true;