Bug 1229519: Fix download managers to pass eslint checks. r=mak
authorDave Townsend <dtownsend@oxymoronical.com>
Thu, 03 Dec 2015 10:00:18 -0800
changeset 275645 70431746380e46188c9b73e830c5eb74c3329399
parent 275644 d05e740814759b053ffaec0ef924e2f916833d31
child 275646 ad36ba7bbf393fa0eb447be9b782122009cea94a
push id68897
push usercbook@mozilla.com
push dateFri, 04 Dec 2015 11:02:38 +0000
treeherdermozilla-inbound@48f854ba48c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs1229519
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1229519: Fix download managers to pass eslint checks. r=mak
toolkit/components/downloads/test/schema_migration/test_migration_to_9.js
toolkit/components/downloads/test/unit/tail_download_manager.js
toolkit/components/downloads/test/unit/test_app_rep.js
toolkit/components/downloads/test/unit/test_app_rep_maclinux.js
toolkit/components/downloads/test/unit/test_app_rep_windows.js
toolkit/components/downloads/test/unit/test_download_samename.js
toolkit/components/downloads/test/unit/test_history_expiration.js
toolkit/components/jsdownloads/src/DownloadCore.jsm
toolkit/components/jsdownloads/src/DownloadImport.jsm
toolkit/components/jsdownloads/src/DownloadList.jsm
toolkit/components/jsdownloads/src/DownloadStore.jsm
toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
toolkit/components/jsdownloads/src/Downloads.jsm
toolkit/components/jsdownloads/src/moz.build
toolkit/components/jsdownloads/test/unit/common_test_Download.js
toolkit/components/jsdownloads/test/unit/head.js
toolkit/components/jsdownloads/test/unit/tail.js
toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
toolkit/components/jsdownloads/test/unit/test_DownloadList.js
toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
toolkit/components/jsdownloads/test/unit/test_Downloads.js
toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
toolkit/mozapps/downloads/DownloadTaskbarProgress.jsm
toolkit/mozapps/downloads/content/downloads.js
toolkit/mozapps/downloads/jar.mn
toolkit/mozapps/downloads/moz.build
toolkit/mozapps/downloads/nsHelperAppDlg.js
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_9.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_9.js
@@ -66,9 +66,9 @@ function run_test()
   do_check_eq(data[i], stmt.getInt32(i++));
   do_check_eq(data[i], stmt.getInt32(i++));
   do_check_true(/^[a-zA-Z0-9\-_]{12}$/.test(stmt.getString(i++)));
 
   stmt.reset();
   stmt.finalize();
 
   cleanup();
-}
\ No newline at end of file
+}
--- a/toolkit/components/downloads/test/unit/tail_download_manager.js
+++ b/toolkit/components/downloads/test/unit/tail_download_manager.js
@@ -8,17 +8,17 @@
  * Provides infrastructure for automated download components tests.
  */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Termination functions common to all tests
 
-add_task(function test_common_terminate()
+add_task(function* test_common_terminate()
 {
   // Stop the HTTP server.  We must do this inside a task in "tail.js" until the
   // xpcshell testing framework supports asynchronous termination functions.
   let deferred = Promise.defer();
   gHttpServer.stop(deferred.resolve);
   yield deferred.promise;
 });
 
--- a/toolkit/components/downloads/test/unit/test_app_rep.js
+++ b/toolkit/components/downloads/test/unit/test_app_rep.js
@@ -154,17 +154,19 @@ add_test(function test_nullSourceURI() {
 add_test(function test_nullCallback() {
   let counts = get_telemetry_counts();
   try {
     gAppRep.queryReputation({
       sourceURI: createURI("http://example.com"),
       fileSize: 12,
     }, null);
     do_throw("Callback cannot be null");
-  } catch (ex if ex.result == Cr.NS_ERROR_INVALID_POINTER) {
+  } catch (ex) {
+    if (ex.result != Cr.NS_ERROR_INVALID_POINTER)
+      throw ex;
     // We don't even increment the count here, because there's no callback.
     check_telemetry(counts.total, counts.shouldBlock, counts.listCounts);
     run_next_test();
   }
 });
 
 // Set up the local whitelist.
 add_test(function test_local_list() {
--- a/toolkit/components/downloads/test/unit/test_app_rep_maclinux.js
+++ b/toolkit/components/downloads/test/unit/test_app_rep_maclinux.js
@@ -205,61 +205,61 @@ function promiseQueryReputation(query, e
     do_check_eq(Cr.NS_OK, aStatus);
     do_check_eq(aShouldBlock, expectedShouldBlock);
     deferred.resolve(true);
   }
   gAppRep.queryReputation(query, onComplete);
   return deferred.promise;
 }
 
-add_task(function()
+add_task(function* ()
 {
   // Wait for Safebrowsing local list updates to complete.
   yield waitForUpdates();
 });
 
-add_task(function test_blocked_binary()
+add_task(function* test_blocked_binary()
 {
   // We should reach the remote server for a verdict.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   // evil.com should return a malware verdict from the remote server.
   yield promiseQueryReputation({sourceURI: createURI("http://evil.com"),
                                 suggestedFileName: "noop.bat",
                                 fileSize: 12}, true);
 });
 
-add_task(function test_non_binary()
+add_task(function* test_non_binary()
 {
   // We should not reach the remote server for a verdict for non-binary files.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/throw");
   yield promiseQueryReputation({sourceURI: createURI("http://evil.com"),
                                 suggestedFileName: "noop.txt",
                                 fileSize: 12}, false);
 });
 
-add_task(function test_good_binary()
+add_task(function* test_good_binary()
 {
   // We should reach the remote server for a verdict.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   // mozilla.com should return a not-guilty verdict from the remote server.
   yield promiseQueryReputation({sourceURI: createURI("http://mozilla.com"),
                                 suggestedFileName: "noop.bat",
                                 fileSize: 12}, false);
 });
 
-add_task(function test_disabled()
+add_task(function* test_disabled()
 {
   // Explicitly disable remote checks
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              false);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/throw");
   let query = {sourceURI: createURI("http://example.com"),
                suggestedFileName: "noop.bat",
@@ -271,17 +271,17 @@ add_task(function test_disabled()
       do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus);
       do_check_false(aShouldBlock);
       deferred.resolve(true);
     }
   );
   yield deferred.promise;
 });
 
-add_task(function test_disabled_through_lists()
+add_task(function* test_disabled_through_lists()
 {
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              false);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   Services.prefs.setCharPref("urlclassifier.downloadBlockTable", "");
   let query = {sourceURI: createURI("http://example.com"),
                suggestedFileName: "noop.bat",
@@ -292,12 +292,12 @@ add_task(function test_disabled_through_
       // We should be getting NS_ERROR_NOT_AVAILABLE if the service is disabled
       do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus);
       do_check_false(aShouldBlock);
       deferred.resolve(true);
     }
   );
   yield deferred.promise;
 });
-add_task(function test_teardown()
+add_task(function* test_teardown()
 {
   gStillRunning = false;
 });
--- a/toolkit/components/downloads/test/unit/test_app_rep_windows.js
+++ b/toolkit/components/downloads/test/unit/test_app_rep_windows.js
@@ -160,17 +160,17 @@ function registerTableUpdate(aTable, aFi
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 function run_test()
 {
   run_next_test();
 }
 
-add_task(function test_setup()
+add_task(function* test_setup()
 {
   // Wait 10 minutes, that is half of the external xpcshell timeout.
   do_timeout(10 * 60 * 1000, function() {
     if (gStillRunning) {
       do_throw("Test timed out.");
     }
   });
   // Set up a local HTTP server to return bad verdicts.
@@ -305,23 +305,23 @@ function promiseQueryReputation(query, e
     do_check_eq(Cr.NS_OK, aStatus);
     do_check_eq(aShouldBlock, expectedShouldBlock);
     deferred.resolve(true);
   }
   gAppRep.queryReputation(query, onComplete);
   return deferred.promise;
 }
 
-add_task(function()
+add_task(function* ()
 {
   // Wait for Safebrowsing local list updates to complete.
   yield waitForUpdates();
 });
 
-add_task(function test_signature_whitelists()
+add_task(function* test_signature_whitelists()
 {
   // We should never get to the remote server.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/throw");
 
   // Use BackgroundFileSaver to extract the signature on Windows.
@@ -342,55 +342,55 @@ add_task(function test_signature_whiteli
 
   // evil.com is not on the allowlist, but this binary is signed by an entity
   // whose certificate information is on the allowlist.
   yield promiseQueryReputation({sourceURI: createURI("http://evil.com"),
                                 signatureInfo: saver.signatureInfo,
                                 fileSize: 12}, false);
 });
 
-add_task(function test_blocked_binary()
+add_task(function* test_blocked_binary()
 {
   // We should reach the remote server for a verdict.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   // evil.com should return a malware verdict from the remote server.
   yield promiseQueryReputation({sourceURI: createURI("http://evil.com"),
                                 suggestedFileName: "noop.bat",
                                 fileSize: 12}, true);
 });
 
-add_task(function test_non_binary()
+add_task(function* test_non_binary()
 {
   // We should not reach the remote server for a verdict for non-binary files.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/throw");
   yield promiseQueryReputation({sourceURI: createURI("http://evil.com"),
                                 suggestedFileName: "noop.txt",
                                 fileSize: 12}, false);
 });
 
-add_task(function test_good_binary()
+add_task(function* test_good_binary()
 {
   // We should reach the remote server for a verdict.
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              true);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   // mozilla.com should return a not-guilty verdict from the remote server.
   yield promiseQueryReputation({sourceURI: createURI("http://mozilla.com"),
                                 suggestedFileName: "noop.bat",
                                 fileSize: 12}, false);
 });
 
-add_task(function test_disabled()
+add_task(function* test_disabled()
 {
   // Explicitly disable remote checks
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              false);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/throw");
   let query = {sourceURI: createURI("http://example.com"),
                suggestedFileName: "noop.bat",
@@ -402,17 +402,17 @@ add_task(function test_disabled()
       do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus);
       do_check_false(aShouldBlock);
       deferred.resolve(true);
     }
   );
   yield deferred.promise;
 });
 
-add_task(function test_disabled_through_lists()
+add_task(function* test_disabled_through_lists()
 {
   Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.enabled",
                              false);
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   Services.prefs.setCharPref("urlclassifier.downloadBlockTable", "");
   let query = {sourceURI: createURI("http://example.com"),
                suggestedFileName: "noop.bat",
@@ -423,12 +423,12 @@ add_task(function test_disabled_through_
       // We should be getting NS_ERROR_NOT_AVAILABLE if the service is disabled
       do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus);
       do_check_false(aShouldBlock);
       deferred.resolve(true);
     }
   );
   yield deferred.promise;
 });
-add_task(function test_teardown()
+add_task(function* test_teardown()
 {
   gStillRunning = false;
 });
--- a/toolkit/components/downloads/test/unit/test_download_samename.js
+++ b/toolkit/components/downloads/test/unit/test_download_samename.js
@@ -94,17 +94,19 @@ function runNextTest()
 {
   if (currentTest == tests.length) {
     for (var file of DownloadListener.prevFiles) {
       try {
         file.remove(false);
       } catch (ex) {
         try {
           do_report_unexpected_exception(ex, "while removing " + file.path);
-        } catch (ex if ex == Components.results.NS_ERROR_ABORT) {
+        } catch (ex) {
+          if (ex != Components.results.NS_ERROR_ABORT)
+            throw ex;
           /* swallow */
         }
       }
     }
     httpserver.stop(do_test_finished);
     return;
   }
   let set = DownloadListener.set = tests[currentTest];
--- a/toolkit/components/downloads/test/unit/test_history_expiration.js
+++ b/toolkit/components/downloads/test/unit/test_history_expiration.js
@@ -28,17 +28,17 @@ function run_test()
 {
   if (oldDownloadManagerDisabled()) {
     return;
   }
 
   run_next_test();
 }
 
-add_task(function test_execute()
+add_task(function* test_execute()
 {
   // Like the code, we check to see if nav-history-service exists
   // (i.e MOZ_PLACES is enabled), so that we don't run this test if it doesn't.
   if (!("@mozilla.org/browser/nav-history-service;1" in Cc))
     return;
 
   let dm = Cc["@mozilla.org/download-manager;1"].
            getService(Ci.nsIDownloadManager);
--- a/toolkit/components/jsdownloads/src/DownloadCore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ -428,17 +428,17 @@ this.Download.prototype = {
 
       if (changeMade) {
         this._notifyChange();
       }
     }
 
     // Now that we stored the promise in the download object, we can start the
     // task that will actually execute the download.
-    deferAttempt.resolve(Task.spawn(function task_D_start() {
+    deferAttempt.resolve(Task.spawn(function* task_D_start() {
       // Wait upon any pending operation before restarting.
       if (this._promiseCanceled) {
         yield this._promiseCanceled;
       }
       if (this._promiseRemovePartialData) {
         try {
           yield this._promiseRemovePartialData;
         } catch (ex) {
@@ -840,17 +840,17 @@ this.Download.prototype = {
     let promiseRemovePartialData = this._promiseRemovePartialData;
 
     if (!promiseRemovePartialData) {
       let deferRemovePartialData = Promise.defer();
       promiseRemovePartialData = deferRemovePartialData.promise;
       this._promiseRemovePartialData = promiseRemovePartialData;
 
       deferRemovePartialData.resolve(
-        Task.spawn(function task_D_removePartialData() {
+        Task.spawn(function* task_D_removePartialData() {
           try {
             // Wait upon any pending cancellation request.
             if (this._promiseCanceled) {
               yield this._promiseCanceled;
             }
             // Ask the saver object to remove any partial data.
             yield this.saver.removePartialData();
             // For completeness, clear the number of bytes transferred.
@@ -903,17 +903,17 @@ this.Download.prototype = {
    * moved or deleted the target file or its associated ".part" file.
    *
    * @return {Promise}
    * @resolves When the operation has completed.
    * @rejects Never.
    */
   refresh: function ()
   {
-    return Task.spawn(function () {
+    return Task.spawn(function* () {
       if (!this.stopped || this._finalized) {
         return;
       }
 
       if (this.succeeded) {
         let oldExists = this.target.exists;
         let oldSize = this.target.size;
         yield this.target.refresh();
@@ -937,17 +937,20 @@ this.Download.prototype = {
 
           // Update the bytes transferred and the related progress properties.
           this.currentBytes = stat.size;
           if (this.totalBytes > 0) {
             this.hasProgress = true;
             this.progress = Math.floor(this.currentBytes /
                                            this.totalBytes * 100);
           }
-        } catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
+        } catch (ex) {
+          if (!(ex instanceof OS.File.Error) || !ex.becauseNoSuchFile) {
+            throw ex;
+          }
           // Ignore the result if the state has changed meanwhile.
           if (!this.stopped || this._finalized) {
             return;
           }
 
           this.hasBlockedData = false;
           this.hasPartialData = false;
         }
@@ -1704,18 +1707,21 @@ this.DownloadSaver.prototype = {
 
     // The start time is always available when we reach this point.
     let startPRTime = this.download.startTime.getTime() * 1000;
 
     try {
       gDownloadHistory.addDownload(sourceUri, referrerUri, startPRTime,
                                    targetUri);
     }
-    catch(ex if ex instanceof Components.Exception &&
-                ex.result == Cr.NS_ERROR_NOT_AVAILABLE) {
+    catch(ex) {
+      if (!(ex instanceof Components.Exception) ||
+          ex.result != Cr.NS_ERROR_NOT_AVAILABLE) {
+        throw ex;
+      }
       //
       // Under normal operation the download history service may not
       // be available. We don't want all downloads that are public to fail
       // when this happens so we'll ignore this error and this error only!
       //
     }
   },
 
@@ -1835,17 +1841,17 @@ this.DownloadCopySaver.prototype = {
 
     this._canceled = false;
 
     let download = this.download;
     let targetPath = download.target.path;
     let partFilePath = download.target.partFilePath;
     let keepPartialData = download.tryToKeepPartialData;
 
-    return Task.spawn(function task_DCS_execute() {
+    return Task.spawn(function* task_DCS_execute() {
       // Add the download to history the first time it is started in this
       // session.  If the download is restarted in a different session, a new
       // history visit will be added.  We do this just to avoid the complexity
       // of serializing this state between sessions, since adding a new visit
       // does not have any noticeable side effect.
       if (!this.alreadyAddedToHistory) {
         this.addToHistory();
         this.alreadyAddedToHistory = true;
@@ -1855,17 +1861,20 @@ this.DownloadCopySaver.prototype = {
       // file name, we should create a placeholder as soon as possible, before
       // starting the network request.  The placeholder is also required in case
       // we are using a ".part" file instead of the final target while the
       // download is in progress.
       try {
         // If the file already exists, don't delete its contents yet.
         let file = yield OS.File.open(targetPath, { write: true });
         yield file.close();
-      } catch (ex if ex instanceof OS.File.Error) {
+      } catch (ex) {
+        if (!(ex instanceof OS.File.Error)) {
+          throw ex;
+        }
         // Throw a DownloadError indicating that the operation failed because of
         // the target file.  We cannot translate this into a specific result
         // code, but we preserve the original message using the toString method.
         let error = new DownloadError({ message: ex.toString() });
         error.becauseTargetFailed = true;
         throw error;
       }
 
@@ -1925,18 +1934,21 @@ this.DownloadCopySaver.prototype = {
           let resumeFromBytes = 0;
           if (channel instanceof Ci.nsIResumableChannel && this.entityID &&
               partFilePath && keepPartialData) {
             try {
               let stat = yield OS.File.stat(partFilePath);
               channel.resumeAt(stat.size, this.entityID);
               resumeAttempted = true;
               resumeFromBytes = stat.size;
-            } catch (ex if ex instanceof OS.File.Error &&
-                           ex.becauseNoSuchFile) { }
+            } catch (ex) {
+              if (!(ex instanceof OS.File.Error) || !ex.becauseNoSuchFile) {
+                throw ex;
+              }
+            }
           }
 
           channel.notificationCallbacks = {
             QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
             getInterface: XPCOMUtils.generateQI([Ci.nsIProgressEventSink]),
             onProgress: function DCSE_onProgress(aRequest, aContext, aProgress,
                                                  aProgressMax)
             {
@@ -1995,18 +2007,21 @@ this.DownloadCopySaver.prototype = {
 
               if (keepPartialData) {
                 // If the source is not resumable, don't keep partial data even
                 // if we were asked to try and do it.
                 if (aRequest instanceof Ci.nsIResumableChannel) {
                   try {
                     // If reading the ID succeeds, the source is resumable.
                     this.entityID = aRequest.entityID;
-                  } catch (ex if ex instanceof Components.Exception &&
-                                 ex.result == Cr.NS_ERROR_NOT_RESUMABLE) {
+                  } catch (ex) {
+                    if (!(ex instanceof Components.Exception) ||
+                        ex.result != Cr.NS_ERROR_NOT_RESUMABLE) {
+                      throw ex;
+                    }
                     keepPartialData = false;
                   }
                 } else {
                   keepPartialData = false;
                 }
               }
 
               // Enable hashing and signature verification before setting the
@@ -2147,21 +2162,25 @@ this.DownloadCopySaver.prototype = {
     }
   },
 
   /**
    * Implements "DownloadSaver.removePartialData".
    */
   removePartialData: function ()
   {
-    return Task.spawn(function task_DCS_removePartialData() {
+    return Task.spawn(function* task_DCS_removePartialData() {
       if (this.download.target.partFilePath) {
         try {
           yield OS.File.remove(this.download.target.partFilePath);
-        } catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) { }
+        } catch (ex) {
+          if (!(ex instanceof OS.File.Error) || !ex.becauseNoSuchFile) {
+            throw ex;
+          }
+        }
       }
     }.bind(this));
   },
 
   /**
    * Implements "DownloadSaver.toSerializable".
    */
   toSerializable: function ()
@@ -2329,18 +2348,22 @@ this.DownloadLegacySaver.prototype = {
   onTransferStarted: function (aRequest, aAlreadyAddedToHistory)
   {
     // Store the entity ID to use for resuming if required.
     if (this.download.tryToKeepPartialData &&
         aRequest instanceof Ci.nsIResumableChannel) {
       try {
         // If reading the ID succeeds, the source is resumable.
         this.entityID = aRequest.entityID;
-      } catch (ex if ex instanceof Components.Exception &&
-                     ex.result == Cr.NS_ERROR_NOT_RESUMABLE) { }
+      } catch (ex) {
+        if (!(ex instanceof Components.Exception) ||
+            ex.result != Cr.NS_ERROR_NOT_RESUMABLE) {
+          throw ex;
+        }
+      }
     }
 
     // For legacy downloads, we must update the referrer at this time.
     if (aRequest instanceof Ci.nsIHttpChannel && aRequest.referrer) {
       this.download.source.referrer = aRequest.referrer.spec;
     }
 
     if (!aAlreadyAddedToHistory) {
@@ -2406,17 +2429,17 @@ this.DownloadLegacySaver.prototype = {
         this.copySaver.entityID = this.entityID;
         this.copySaver.alreadyAddedToHistory = true;
       }
       return this.copySaver.execute.apply(this.copySaver, arguments);
     }
 
     this.setProgressBytesFn = aSetProgressBytesFn;
 
-    return Task.spawn(function task_DLS_execute() {
+    return Task.spawn(function* task_DLS_execute() {
       try {
         // Wait for the component that executes the download to finish.
         yield this.deferExecuted.promise;
 
         // At this point, the "request" property has been populated.  Ensure we
         // report the value of "Content-Length", if available, even if the
         // download didn't generate any progress events.
         if (!this.progressWasNotified &&
@@ -2436,17 +2459,21 @@ this.DownloadLegacySaver.prototype = {
         // source).  In this case, ensure that an empty file is created as
         // expected.
         if (!this.download.target.partFilePath) {
           try {
             // This atomic operation is more efficient than an existence check.
             let file = yield OS.File.open(this.download.target.path,
                                           { create: true });
             yield file.close();
-          } catch (ex if ex instanceof OS.File.Error && ex.becauseExists) { }
+          } catch (ex) {
+            if (!(ex instanceof OS.File.Error) || !ex.becauseExists) {
+              throw ex;
+            }
+          }
         }
 
         yield this._checkReputationAndMove();
 
       } catch (ex) {
         // Ensure we always remove the final target file on failure,
         // independently of which code path failed.  In some cases, the
         // component executing the download may have already removed the file.
@@ -2618,17 +2645,17 @@ this.DownloadPDFSaver.prototype = {
    */
   _webBrowserPrint: null,
 
   /**
    * Implements "DownloadSaver.execute".
    */
   execute: function (aSetProgressBytesFn, aSetPropertiesFn)
   {
-    return Task.spawn(function task_DCS_execute() {
+    return Task.spawn(function* task_DCS_execute() {
       if (!this.download.source.windowRef) {
         throw new DownloadError({
           message: "PDF saver must be passed an open window, and cannot be restarted.",
           becauseSourceFailed: true,
         });
       }
 
       let win = this.download.source.windowRef.get();
--- a/toolkit/components/jsdownloads/src/DownloadImport.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadImport.jsm
@@ -66,17 +66,17 @@ this.DownloadImport.prototype = {
    * format. Each imported download will be added to the DownloadList
    *
    * @return {Promise}
    * @resolves When the operation has completed (i.e., every download
    *           from the previous database has been read and added to
    *           the DownloadList)
    */
   import: function () {
-    return Task.spawn(function task_DI_import() {
+    return Task.spawn(function* task_DI_import() {
       let connection = yield Sqlite.openConnection({ path: this.path });
 
       try {
         let schemaVersion = yield connection.getSchemaVersion();
         // We don't support schemas older than version 7 (from 2007)
         // - Version 7 added the columns mimeType, preferredApplication
         //   and preferredAction in 2007
         // - Version 8 added the column autoResume in 2007
--- a/toolkit/components/jsdownloads/src/DownloadList.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadList.jsm
@@ -228,17 +228,17 @@ this.DownloadList.prototype = {
    *
    * @param aFilterFn
    *        The filter function is called with each download as its only
    *        argument, and should return true to remove the download and false
    *        to keep it.  This parameter may be null or omitted to have no
    *        additional filter.
    */
   removeFinished: function DL_removeFinished(aFilterFn) {
-    Task.spawn(function() {
+    Task.spawn(function* () {
       let list = yield this.getAll();
       for (let download of list) {
         // Remove downloads that have been canceled, even if the cancellation
         // operation hasn't completed yet so we don't check "stopped" here.
         // Failed downloads with partial data are also removed.
         if (download.stopped && (!download.hasPartialData || download.error) &&
             (!aFilterFn || aFilterFn(download))) {
           // Remove the download first, so that the views don't get the change
--- a/toolkit/components/jsdownloads/src/DownloadStore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadStore.jsm
@@ -98,21 +98,24 @@ this.DownloadStore.prototype = {
    * Loads persistent downloads from the file to the list.
    *
    * @return {Promise}
    * @resolves When the operation finished successfully.
    * @rejects JavaScript exception.
    */
   load: function DS_load()
   {
-    return Task.spawn(function task_DS_load() {
+    return Task.spawn(function* task_DS_load() {
       let bytes;
       try {
         bytes = yield OS.File.read(this.path);
-      } catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
+      } catch (ex) {
+        if (!(ex instanceof OS.File.Error) || !ex.becauseNoSuchFile) {
+          throw ex;
+        }
         // If the file does not exist, there are no downloads to load.
         return;
       }
 
       let storeData = JSON.parse(gTextDecoder.decode(bytes));
 
       // Create live downloads based on the static snapshot.
       for (let downloadData of storeData.list) {
@@ -148,17 +151,17 @@ this.DownloadStore.prototype = {
    * If an error occurs, the previous file is not deleted.
    *
    * @return {Promise}
    * @resolves When the operation finished successfully.
    * @rejects JavaScript exception.
    */
   save: function DS_save()
   {
-    return Task.spawn(function task_DS_save() {
+    return Task.spawn(function* task_DS_save() {
       let downloads = yield this.list.getAll();
 
       // Take a static snapshot of the current state of all the downloads.
       let storeData = { list: [] };
       let atLeastOneDownload = false;
       for (let download of downloads) {
         try {
           if (!this.onsaveitem(download)) {
@@ -183,17 +186,20 @@ this.DownloadStore.prototype = {
         // Create or overwrite the file if there are downloads to save.
         let bytes = gTextEncoder.encode(JSON.stringify(storeData));
         yield OS.File.writeAtomic(this.path, bytes,
                                   { tmpPath: this.path + ".tmp" });
       } else {
         // Remove the file if there are no downloads to save at all.
         try {
           yield OS.File.remove(this.path);
-        } catch (ex if ex instanceof OS.File.Error &&
-                 (ex.becauseNoSuchFile || ex.becauseAccessDenied)) {
+        } catch (ex) {
+          if (!(ex instanceof OS.File.Error) ||
+              !(ex.becauseNoSuchFile || ex.becauseAccessDenied)) {
+            throw ex;
+          }
           // On Windows, we may get an access denied error instead of a no such
           // file error if the file existed before, and was recently deleted.
         }
       }
     }.bind(this));
   },
 };
--- a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
@@ -18,16 +18,17 @@ this.EXPORTED_SYMBOLS = [
 //// Globals
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
@@ -103,22 +104,22 @@ XPCOMUtils.defineLazyGetter(DownloadUIHe
  * Allows displaying prompts related to downloads.
  *
  * @param aParent
  *        The nsIDOMWindow to which prompts should be attached, or null to
  *        attach prompts to the most recently active window.
  */
 this.DownloadPrompter = function (aParent)
 {
-#ifdef MOZ_B2G
-  // On B2G there is no prompter implementation.
-  this._prompter = null;
-#else
-  this._prompter = Services.ww.getNewPrompter(aParent);
-#endif
+  if (AppConstants.MOZ_B2G) {
+    // On B2G there is no prompter implementation.
+    this._prompter = null;
+  } else {
+    this._prompter = Services.ww.getNewPrompter(aParent);
+  }
 }
 
 this.DownloadPrompter.prototype = {
   /**
    * Constants with the different type of prompts.
    */
   ON_QUIT: "prompt-on-quit",
   ON_OFFLINE: "prompt-on-offline",
@@ -205,27 +206,27 @@ this.DownloadPrompter.prototype = {
                       (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
     let okButton = aDownloadsCount > 1 ? s.cancelDownloadsOKTextMultiple(aDownloadsCount)
                                        : s.cancelDownloadsOKText;
     let title, message, cancelButton;
 
     switch (aPromptType) {
       case this.ON_QUIT:
         title = s.quitCancelDownloadsAlertTitle;
-#ifndef XP_MACOSX
-        message = aDownloadsCount > 1
-                  ? s.quitCancelDownloadsAlertMsgMultiple(aDownloadsCount)
-                  : s.quitCancelDownloadsAlertMsg;
-        cancelButton = s.dontQuitButtonWin;
-#else
-        message = aDownloadsCount > 1
-                  ? s.quitCancelDownloadsAlertMsgMacMultiple(aDownloadsCount)
-                  : s.quitCancelDownloadsAlertMsgMac;
-        cancelButton = s.dontQuitButtonMac;
-#endif
+        if (AppConstants.platform != "macosx") {
+          message = aDownloadsCount > 1
+                    ? s.quitCancelDownloadsAlertMsgMultiple(aDownloadsCount)
+                    : s.quitCancelDownloadsAlertMsg;
+          cancelButton = s.dontQuitButtonWin;
+        } else {
+          message = aDownloadsCount > 1
+                    ? s.quitCancelDownloadsAlertMsgMacMultiple(aDownloadsCount)
+                    : s.quitCancelDownloadsAlertMsgMac;
+          cancelButton = s.dontQuitButtonMac;
+        }
         break;
       case this.ON_OFFLINE:
         title = s.offlineCancelDownloadsAlertTitle;
         message = aDownloadsCount > 1
                   ? s.offlineCancelDownloadsAlertMsgMultiple(aDownloadsCount)
                   : s.offlineCancelDownloadsAlertMsg;
         cancelButton = s.dontGoOfflineButton;
         break;
--- a/toolkit/components/jsdownloads/src/Downloads.jsm
+++ b/toolkit/components/jsdownloads/src/Downloads.jsm
@@ -167,17 +167,17 @@ this.Downloads = {
    *
    * @return {Promise}
    * @resolves The requested DownloadList or DownloadCombinedList object.
    * @rejects JavaScript exception.
    */
   getList: function (aType)
   {
     if (!this._promiseListsInitialized) {
-      this._promiseListsInitialized = Task.spawn(function () {
+      this._promiseListsInitialized = Task.spawn(function* () {
         let publicList = new DownloadList();
         let privateList = new DownloadList();
         let combinedList = new DownloadCombinedList(publicList, privateList);
 
         try {
           yield DownloadIntegration.addListObservers(publicList, false);
           yield DownloadIntegration.addListObservers(privateList, true);
           yield DownloadIntegration.initializePublicDownloadList(publicList);
--- a/toolkit/components/jsdownloads/src/moz.build
+++ b/toolkit/components/jsdownloads/src/moz.build
@@ -14,21 +14,21 @@ EXTRA_COMPONENTS += [
 ]
 
 EXTRA_JS_MODULES += [
     'DownloadCore.jsm',
     'DownloadImport.jsm',
     'DownloadList.jsm',
     'Downloads.jsm',
     'DownloadStore.jsm',
+    'DownloadUIHelper.jsm',
 ]
 
 EXTRA_PP_JS_MODULES += [
     'DownloadIntegration.jsm',
-    'DownloadUIHelper.jsm',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 CXXFLAGS += CONFIG['TK_CFLAGS']
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -46,17 +46,17 @@ function promiseStartDownload(aSourceUrl
  * This function uses either DownloadCopySaver or DownloadLegacySaver based on
  * the current test run.
  *
  * @return {Promise}
  * @resolves The newly created Download object, still in progress.
  * @rejects JavaScript exception.
  */
 function promiseStartDownload_tryToKeepPartialData() {
-  return Task.spawn(function () {
+  return Task.spawn(function* () {
     mustInterruptResponses();
 
     // Start a new download and configure it to keep partially downloaded data.
     let download;
     if (!gUseLegacySaver) {
       let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
       download = yield Downloads.createDownload({
         source: httpUrl("interruptible_resumable.txt"),
@@ -69,40 +69,43 @@ function promiseStartDownload_tryToKeepP
       // Start a download using nsIExternalHelperAppService, that is configured
       // to keep partially downloaded data by default.
       download = yield promiseStartExternalHelperAppServiceDownload();
     }
 
     yield promiseDownloadMidway(download);
     yield promisePartFileReady(download);
 
-    throw new Task.Result(download);
+    return download;
   });
 }
 
 /**
  * This function should be called after the progress notification for a download
  * is received, and waits for the worker thread of BackgroundFileSaver to
  * receive the data to be written to the ".part" file on disk.
  *
  * @return {Promise}
  * @resolves When the ".part" file has been written to disk.
  * @rejects JavaScript exception.
  */
 function promisePartFileReady(aDownload) {
-  return Task.spawn(function () {
+  return Task.spawn(function* () {
     // We don't have control over the file output code in BackgroundFileSaver.
     // After we receive the download progress notification, we may only check
     // that the ".part" file has been created, while its size cannot be
     // determined because the file is currently open.
     try {
       do {
         yield promiseTimeout(50);
       } while (!(yield OS.File.exists(aDownload.target.partFilePath)));
-    } catch (ex if ex instanceof OS.File.Error) {
+    } catch (ex) {
+      if (!(ex instanceof OS.File.Error)) {
+        throw ex;
+      }
       // This indicates that the file has been created and cannot be accessed.
       // The specific error might vary with the platform.
       do_print("Expected exception while checking existence: " + ex.toString());
       // Wait some more time to allow the write to complete.
       yield promiseTimeout(100);
     }
   });
 }
@@ -130,17 +133,17 @@ var promiseVerifyTarget = Task.async(fun
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
  * Executes a download and checks its basic properties after construction.
  * The download is started by constructing the simplest Download object with
  * the "copy" saver, or using the legacy nsITransfer interface.
  */
-add_task(function test_basic()
+add_task(function* test_basic()
 {
   let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
 
   let download;
   if (!gUseLegacySaver) {
     // When testing DownloadCopySaver, we have control over the download, thus
     // we can check its basic properties before it starts.
     download = yield Downloads.createDownload({
@@ -171,32 +174,32 @@ add_task(function test_basic()
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 });
 
 /**
  * Executes a download with the tryToKeepPartialData property set, and ensures
  * that the file is saved correctly.  When testing DownloadLegacySaver, the
  * download is executed using the nsIExternalHelperAppService component.
  */
-add_task(function test_basic_tryToKeepPartialData()
+add_task(function* test_basic_tryToKeepPartialData()
 {
   let download = yield promiseStartDownload_tryToKeepPartialData();
   continueResponses();
   yield promiseDownloadStopped(download);
 
   // The target file should now have been created, and the ".part" file deleted.
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
   do_check_false(yield OS.File.exists(download.target.partFilePath));
   do_check_eq(32, download.saver.getSha256Hash().length);
 });
 
 /**
  * Tests the permissions of the final target file once the download finished.
  */
-add_task(function test_unix_permissions()
+add_task(function* test_unix_permissions()
 {
   // This test is only executed on some Desktop systems.
   if (Services.appinfo.OS != "Darwin" && Services.appinfo.OS != "Linux" &&
       Services.appinfo.OS != "WINNT") {
     do_print("Skipping test.");
     return;
   }
 
@@ -249,17 +252,17 @@ add_task(function test_unix_permissions(
 
   // Clean up the changes to the preference.
   Services.prefs.clearUserPref(kDeleteTempFileOnExit);
 });
 
 /**
  * Checks the referrer for downloads.
  */
-add_task(function test_referrer()
+add_task(function* test_referrer()
 {
   let sourcePath = "/test_referrer.txt";
   let sourceUrl = httpUrl("test_referrer.txt");
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
 
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
   }
@@ -296,17 +299,17 @@ add_task(function test_referrer()
   yield download.start();
 
   cleanup();
 });
 
 /**
  * Checks initial and final state and progress for a successful download.
  */
-add_task(function test_initial_final_state()
+add_task(function* test_initial_final_state()
 {
   let download;
   if (!gUseLegacySaver) {
     // When testing DownloadCopySaver, we have control over the download, thus
     // we can check its state before it starts.
     download = yield promiseNewDownload();
 
     do_check_true(download.stopped);
@@ -334,17 +337,17 @@ add_task(function test_initial_final_sta
   do_check_true(isValidDate(download.startTime));
   do_check_true(download.target.exists);
   do_check_eq(download.target.size, TEST_DATA_SHORT.length);
 });
 
 /**
  * Checks the notification of the final download state.
  */
-add_task(function test_final_state_notified()
+add_task(function* test_final_state_notified()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   let onchangeNotified = false;
   let lastNotifiedStopped;
   let lastNotifiedProgress;
@@ -363,17 +366,17 @@ add_task(function test_final_state_notif
   do_check_true(onchangeNotified);
   do_check_true(lastNotifiedStopped);
   do_check_eq(lastNotifiedProgress, 100);
 });
 
 /**
  * Checks intermediate progress for a successful download.
  */
-add_task(function test_intermediate_progress()
+add_task(function* test_intermediate_progress()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   yield promiseDownloadMidway(download);
 
   do_check_true(download.hasProgress);
@@ -392,17 +395,17 @@ add_task(function test_intermediate_prog
   do_check_eq(download.progress, 100);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Downloads a file with a "Content-Length" of 0 and checks the progress.
  */
-add_task(function test_empty_progress()
+add_task(function* test_empty_progress()
 {
   let download = yield promiseStartDownload(httpUrl("empty.txt"));
   yield promiseDownloadStopped(download);
 
   do_check_true(download.stopped);
   do_check_true(download.hasProgress);
   do_check_eq(download.progress, 100);
   do_check_eq(download.currentBytes, 0);
@@ -415,17 +418,17 @@ add_task(function test_empty_progress()
   do_check_true(download.target.exists);
   do_check_eq(download.target.size, 0);
 });
 
 /**
  * Downloads a file with a "Content-Length" of 0 with the tryToKeepPartialData
  * property set, and ensures that the file is saved correctly.
  */
-add_task(function test_empty_progress_tryToKeepPartialData()
+add_task(function* test_empty_progress_tryToKeepPartialData()
 {
   // Start a new download and configure it to keep partially downloaded data.
   let download;
   if (!gUseLegacySaver) {
     let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
     download = yield Downloads.createDownload({
       source: httpUrl("empty.txt"),
       target: { path: targetFilePath,
@@ -448,17 +451,17 @@ add_task(function test_empty_progress_tr
 
   do_check_false(yield OS.File.exists(download.target.partFilePath));
   do_check_eq(32, download.saver.getSha256Hash().length);
 });
 
 /**
  * Downloads an empty file with no "Content-Length" and checks the progress.
  */
-add_task(function test_empty_noprogress()
+add_task(function* test_empty_noprogress()
 {
   let sourcePath = "/test_empty_noprogress.txt";
   let sourceUrl = httpUrl("test_empty_noprogress.txt");
   let deferRequestReceived = Promise.defer();
 
   // Register an interruptible handler that notifies us when the request occurs.
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
@@ -525,17 +528,17 @@ add_task(function test_empty_noprogress(
   do_check_eq(download.target.size, 0);
 
   do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
 });
 
 /**
  * Calls the "start" method two times before the download is finished.
  */
-add_task(function test_start_twice()
+add_task(function* test_start_twice()
 {
   mustInterruptResponses();
 
   let download;
   if (!gUseLegacySaver) {
     // When testing DownloadCopySaver, we have control over the download, thus
     // we can start the download later during the test.
     download = yield promiseNewDownload(httpUrl("interruptible.txt"));
@@ -562,17 +565,17 @@ add_task(function test_start_twice()
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download and verifies that its state is reported correctly.
  */
-add_task(function test_cancel_midway()
+add_task(function* test_cancel_midway()
 {
   mustInterruptResponses();
 
   // In this test case, we execute different checks that are only possible with
   // DownloadCopySaver or DownloadLegacySaver respectively.
   let download;
   let options = {};
   if (!gUseLegacySaver) {
@@ -628,28 +631,31 @@ add_task(function test_cancel_midway()
   do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
   do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
 
   if (!gUseLegacySaver) {
     // The promise returned by "start" should have been rejected meanwhile.
     try {
       yield promiseAttempt;
       do_throw("The download should have been canceled.");
-    } catch (ex if ex instanceof Downloads.Error) {
+    } catch (ex) {
+      if (!(ex instanceof Downloads.Error)) {
+        throw ex;
+      }
       do_check_false(ex.becauseSourceFailed);
       do_check_false(ex.becauseTargetFailed);
     }
   }
 });
 
 /**
  * Cancels a download while keeping partially downloaded data, and verifies that
  * both the target file and the ".part" file are deleted.
  */
-add_task(function test_cancel_midway_tryToKeepPartialData()
+add_task(function* test_cancel_midway_tryToKeepPartialData()
 {
   let download = yield promiseStartDownload_tryToKeepPartialData();
 
   do_check_true(yield OS.File.exists(download.target.path));
   do_check_true(yield OS.File.exists(download.target.partFilePath));
 
   yield download.cancel();
   yield download.removePartialData();
@@ -660,17 +666,17 @@ add_task(function test_cancel_midway_try
 
   do_check_false(yield OS.File.exists(download.target.path));
   do_check_false(yield OS.File.exists(download.target.partFilePath));
 });
 
 /**
  * Cancels a download right after starting it.
  */
-add_task(function test_cancel_immediately()
+add_task(function* test_cancel_immediately()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   let promiseAttempt = download.start();
   do_check_false(download.stopped);
 
@@ -678,17 +684,20 @@ add_task(function test_cancel_immediatel
   do_check_true(download.canceled);
 
   // At this point, we don't know whether the download has already stopped or
   // is still waiting for cancellation.  We can wait on the promise returned
   // by the "start" method to know for sure.
   try {
     yield promiseAttempt;
     do_throw("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error)) {
+      throw ex;
+    }
     do_check_false(ex.becauseSourceFailed);
     do_check_false(ex.becauseTargetFailed);
   }
 
   do_check_true(download.stopped);
   do_check_true(download.canceled);
   do_check_true(download.error === null);
 
@@ -696,17 +705,17 @@ add_task(function test_cancel_immediatel
 
   // Check that the promise returned by the "cancel" method has been resolved.
   yield promiseCancel;
 });
 
 /**
  * Cancels and restarts a download sequentially.
  */
-add_task(function test_cancel_midway_restart()
+add_task(function* test_cancel_midway_restart()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   // The first time, cancel the download midway.
   yield promiseDownloadMidway(download);
   yield download.cancel();
@@ -738,17 +747,17 @@ add_task(function test_cancel_midway_res
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download and restarts it from where it stopped.
  */
-add_task(function test_cancel_midway_restart_tryToKeepPartialData()
+add_task(function* test_cancel_midway_restart_tryToKeepPartialData()
 {
   let download = yield promiseStartDownload_tryToKeepPartialData();
   yield download.cancel();
 
   do_check_true(download.stopped);
   do_check_true(download.hasPartialData);
 
   // The target file should not exist, but we should have kept the partial data.
@@ -792,17 +801,17 @@ add_task(function test_cancel_midway_res
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
   do_check_false(yield OS.File.exists(download.target.partFilePath));
 });
 
 /**
  * Cancels a download while keeping partially downloaded data, then removes the
  * data and restarts the download from the beginning.
  */
-add_task(function test_cancel_midway_restart_removePartialData()
+add_task(function* test_cancel_midway_restart_removePartialData()
 {
   let download = yield promiseStartDownload_tryToKeepPartialData();
   yield download.cancel();
 
   do_check_true(download.hasPartialData);
   yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
   do_check_false(download.target.exists);
   do_check_eq(download.target.size, 0);
@@ -826,17 +835,17 @@ add_task(function test_cancel_midway_res
   do_check_false(yield OS.File.exists(download.target.partFilePath));
 });
 
 /**
  * Cancels a download while keeping partially downloaded data, then removes the
  * data and restarts the download from the beginning without keeping the partial
  * data anymore.
  */
-add_task(function test_cancel_midway_restart_tryToKeepPartialData_false()
+add_task(function* test_cancel_midway_restart_tryToKeepPartialData_false()
 {
   let download = yield promiseStartDownload_tryToKeepPartialData();
   yield download.cancel();
 
   download.tryToKeepPartialData = false;
 
   // The above property change does not affect existing partial data.
   do_check_true(download.hasPartialData);
@@ -879,17 +888,17 @@ add_task(function test_cancel_midway_res
   // The target file should now have been created, and the ".part" file deleted.
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
   do_check_false(yield OS.File.exists(download.target.partFilePath));
 });
 
 /**
  * Cancels a download right after starting it, then restarts it immediately.
  */
-add_task(function test_cancel_immediately_restart_immediately()
+add_task(function* test_cancel_immediately_restart_immediately()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
   let promiseAttempt = download.start();
 
   do_check_false(download.stopped);
 
@@ -913,17 +922,20 @@ add_task(function test_cancel_immediatel
   // the canceled request was received by the server or not.
   continueResponses();
   try {
     yield promiseAttempt;
     // If we get here, it means that the first attempt actually succeeded.  In
     // fact, this could be a valid outcome, because the cancellation request may
     // not have been processed in time before the download finished.
     do_print("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error)) {
+      throw ex;
+    }
     do_check_false(ex.becauseSourceFailed);
     do_check_false(ex.becauseTargetFailed);
   }
 
   yield promiseRestarted;
 
   do_check_true(download.stopped);
   do_check_true(download.succeeded);
@@ -931,17 +943,17 @@ add_task(function test_cancel_immediatel
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download midway, then restarts it immediately.
  */
-add_task(function test_cancel_midway_restart_immediately()
+add_task(function* test_cancel_midway_restart_immediately()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
   let promiseAttempt = download.start();
 
   // The first time, cancel the download midway.
   yield promiseDownloadMidway(download);
@@ -961,17 +973,20 @@ add_task(function test_cancel_midway_res
   do_check_eq(download.totalBytes, 0);
   do_check_eq(download.currentBytes, 0);
 
   // The second request is allowed to complete.
   continueResponses();
   try {
     yield promiseAttempt;
     do_throw("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error)) {
+      throw ex;
+    }
     do_check_false(ex.becauseSourceFailed);
     do_check_false(ex.becauseTargetFailed);
   }
 
   yield promiseRestarted;
 
   do_check_true(download.stopped);
   do_check_true(download.succeeded);
@@ -979,17 +994,17 @@ add_task(function test_cancel_midway_res
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Calls the "cancel" method on a successful download.
  */
-add_task(function test_cancel_successful()
+add_task(function* test_cancel_successful()
 {
   let download = yield promiseStartDownload();
   yield promiseDownloadStopped(download);
 
   // The cancel method should succeed with no effect.
   yield download.cancel();
 
   do_check_true(download.stopped);
@@ -998,33 +1013,36 @@ add_task(function test_cancel_successful
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 });
 
 /**
  * Calls the "cancel" method two times in a row.
  */
-add_task(function test_cancel_twice()
+add_task(function* test_cancel_twice()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   let promiseAttempt = download.start();
   do_check_false(download.stopped);
 
   let promiseCancel1 = download.cancel();
   do_check_true(download.canceled);
   let promiseCancel2 = download.cancel();
 
   try {
     yield promiseAttempt;
     do_throw("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error)) {
+      throw ex;
+    }
     do_check_false(ex.becauseSourceFailed);
     do_check_false(ex.becauseTargetFailed);
   }
 
   // Both promises should now be resolved.
   yield promiseCancel1;
   yield promiseCancel2;
 
@@ -1034,17 +1052,17 @@ add_task(function test_cancel_twice()
   do_check_true(download.error === null);
 
   do_check_false(yield OS.File.exists(download.target.path));
 });
 
 /**
  * Checks the "refresh" method for succeeded downloads.
  */
-add_task(function test_refresh_succeeded()
+add_task(function* test_refresh_succeeded()
 {
   let download = yield promiseStartDownload();
   yield promiseDownloadStopped(download);
 
   // The DownloadTarget properties should be the same after calling "refresh".
   yield download.refresh();
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 
@@ -1059,17 +1077,17 @@ add_task(function test_refresh_succeeded
   yield OS.File.move(download.target.path + ".old", download.target.path);
   yield download.refresh();
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 });
 
 /**
  * Checks that a download cannot be restarted after the "finalize" method.
  */
-add_task(function test_finalize()
+add_task(function* test_finalize()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   let promiseFinalized = download.finalize();
 
   try {
@@ -1085,17 +1103,17 @@ add_task(function test_finalize()
   do_check_true(download.error === null);
 
   do_check_false(yield OS.File.exists(download.target.path));
 });
 
 /**
  * Checks that the "finalize" method can remove partially downloaded data.
  */
-add_task(function test_finalize_tryToKeepPartialData()
+add_task(function* test_finalize_tryToKeepPartialData()
 {
   // Check finalization without removing partial data.
   let download = yield promiseStartDownload_tryToKeepPartialData();
   yield download.finalize();
 
   do_check_true(download.hasPartialData);
   do_check_true(yield OS.File.exists(download.target.partFilePath));
 
@@ -1108,17 +1126,17 @@ add_task(function test_finalize_tryToKee
 
   do_check_false(download.hasPartialData);
   do_check_false(yield OS.File.exists(download.target.partFilePath));
 });
 
 /**
  * Checks that whenSucceeded returns a promise that is resolved after a restart.
  */
-add_task(function test_whenSucceeded_after_restart()
+add_task(function* test_whenSucceeded_after_restart()
 {
   mustInterruptResponses();
 
   let promiseSucceeded;
 
   let download;
   if (!gUseLegacySaver) {
     // When testing DownloadCopySaver, we have control over the download, thus
@@ -1149,17 +1167,17 @@ add_task(function test_whenSucceeded_aft
   do_check_true(download.error === null);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Ensures download error details are reported on network failures.
  */
-add_task(function test_error_source()
+add_task(function* test_error_source()
 {
   let serverSocket = startFakeServer();
   try {
     let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
 
     let download;
     try {
       if (!gUseLegacySaver) {
@@ -1174,17 +1192,20 @@ add_task(function test_error_source()
         // When testing DownloadLegacySaver, we cannot be sure whether we are
         // testing the promise returned by the "start" method or we are testing
         // the "error" property checked by promiseDownloadStopped.  This happens
         // because we don't have control over when the download is started.
         download = yield promiseStartLegacyDownload(sourceUrl);
         yield promiseDownloadStopped(download);
       }
       do_throw("The download should have failed.");
-    } catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) {
+    } catch (ex) {
+      if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
+        throw ex;
+      }
       // A specific error object is thrown when reading from the source fails.
     }
 
     // Check the properties now that the download stopped.
     do_check_true(download.stopped);
     do_check_false(download.canceled);
     do_check_true(download.error !== null);
     do_check_true(download.error.becauseSourceFailed);
@@ -1197,17 +1218,17 @@ add_task(function test_error_source()
     serverSocket.close();
   }
 });
 
 /**
  * Ensures a download error is reported when receiving less bytes than what was
  * specified in the Content-Length header.
  */
-add_task(function test_error_source_partial()
+add_task(function* test_error_source_partial()
 {
   let sourceUrl = httpUrl("shorter-than-content-length-http-1-1.txt");
 
   let enforcePref = Services.prefs.getBoolPref("network.http.enforce-framing.http1");
   Services.prefs.setBoolPref("network.http.enforce-framing.http1", true);
 
   function cleanup() {
     Services.prefs.setBoolPref("network.http.enforce-framing.http1", enforcePref);
@@ -1228,17 +1249,20 @@ add_task(function test_error_source_part
       // When testing DownloadLegacySaver, we cannot be sure whether we are
       // testing the promise returned by the "start" method or we are testing
       // the "error" property checked by promiseDownloadStopped.  This happens
       // because we don't have control over when the download is started.
       download = yield promiseStartLegacyDownload(sourceUrl);
       yield promiseDownloadStopped(download);
     }
     do_throw("The download should have failed.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
+      throw ex;
+    }
     // A specific error object is thrown when reading from the source fails.
   }
 
   // Check the properties now that the download stopped.
   do_check_true(download.stopped);
   do_check_false(download.canceled);
   do_check_true(download.error !== null);
   do_check_true(download.error.becauseSourceFailed);
@@ -1248,17 +1272,17 @@ add_task(function test_error_source_part
   do_check_false(yield OS.File.exists(download.target.path));
   do_check_false(download.target.exists);
   do_check_eq(download.target.size, 0);
 });
 
 /**
  * Ensures download error details are reported on local writing failures.
  */
-add_task(function test_error_target()
+add_task(function* test_error_target()
 {
   // Create a file without write access permissions before downloading.
   let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
   targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
   try {
     let download;
     try {
       if (!gUseLegacySaver) {
@@ -1274,17 +1298,20 @@ add_task(function test_error_target()
         // testing the promise returned by the "start" method or we are testing
         // the "error" property checked by promiseDownloadStopped.  This happens
         // because we don't have control over when the download is started.
         download = yield promiseStartLegacyDownload(null,
                                                     { targetFile: targetFile });
         yield promiseDownloadStopped(download);
       }
       do_throw("The download should have failed.");
-    } catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
+    } catch (ex) {
+      if (!(ex instanceof Downloads.Error) || !ex.becauseTargetFailed) {
+        throw ex;
+      }
       // A specific error object is thrown when writing to the target fails.
     }
 
     // Check the properties now that the download stopped.
     do_check_true(download.stopped);
     do_check_false(download.canceled);
     do_check_true(download.error !== null);
     do_check_true(download.error.becauseTargetFailed);
@@ -1296,17 +1323,17 @@ add_task(function test_error_target()
       targetFile.remove(false);
     }
   }
 });
 
 /**
  * Restarts a failed download.
  */
-add_task(function test_error_restart()
+add_task(function* test_error_restart()
 {
   let download;
 
   // Create a file without write access permissions before downloading.
   let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
   targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
   try {
     // Use DownloadCopySaver or DownloadLegacySaver based on the test run,
@@ -1318,17 +1345,20 @@ add_task(function test_error_restart()
       });
       download.start();
     } else {
       download = yield promiseStartLegacyDownload(null,
                                                   { targetFile: targetFile });
     }
     yield promiseDownloadStopped(download);
     do_throw("The download should have failed.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseTargetFailed) {
+      throw ex;
+    }
     // A specific error object is thrown when writing to the target fails.
   } finally {
     // Restore the default permissions to allow deleting the file on Windows.
     if (targetFile.exists()) {
       targetFile.permissions = FileUtils.PERMS_FILE;
 
       // Also for Windows, rename the file before deleting.  This makes the
       // current file name available immediately for a new file, while deleting
@@ -1348,17 +1378,17 @@ add_task(function test_error_restart()
   do_check_eq(download.progress, 100);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 });
 
 /**
  * Executes download in both public and private modes.
  */
-add_task(function test_public_and_private()
+add_task(function* test_public_and_private()
 {
   let sourcePath = "/test_public_and_private.txt";
   let sourceUrl = httpUrl("test_public_and_private.txt");
   let testCount = 0;
 
   // Apply pref to allow all cookies.
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
 
@@ -1405,17 +1435,17 @@ add_task(function test_public_and_privat
   }
 
   cleanup();
 });
 
 /**
  * Checks the startTime gets updated even after a restart.
  */
-add_task(function test_cancel_immediately_restart_and_check_startTime()
+add_task(function* test_cancel_immediately_restart_and_check_startTime()
 {
   let download = yield promiseStartDownload();
 
   let startTime = download.startTime;
   do_check_true(isValidDate(download.startTime));
 
   yield download.cancel();
   do_check_eq(download.startTime.getTime(), startTime.getTime());
@@ -1425,17 +1455,17 @@ add_task(function test_cancel_immediatel
 
   yield download.start();
   do_check_true(download.startTime.getTime() > startTime.getTime());
 });
 
 /**
  * Executes download with content-encoding.
  */
-add_task(function test_with_content_encoding()
+add_task(function* test_with_content_encoding()
 {
   let sourcePath = "/test_with_content_encoding.txt";
   let sourceUrl = httpUrl("test_with_content_encoding.txt");
 
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
   }
   do_register_cleanup(cleanup);
@@ -1461,17 +1491,17 @@ add_task(function test_with_content_enco
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 
   cleanup();
 });
 
 /**
  * Checks that the file is not decoded if the extension matches the encoding.
  */
-add_task(function test_with_content_encoding_ignore_extension()
+add_task(function* test_with_content_encoding_ignore_extension()
 {
   let sourcePath = "/test_with_content_encoding_ignore_extension.gz";
   let sourceUrl = httpUrl("test_with_content_encoding_ignore_extension.gz");
 
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
   }
   do_register_cleanup(cleanup);
@@ -1500,17 +1530,17 @@ add_task(function test_with_content_enco
         String.fromCharCode.apply(String, TEST_DATA_SHORT_GZIP_ENCODED));
 
   cleanup();
 });
 
 /**
  * Cancels and restarts a download sequentially with content-encoding.
  */
-add_task(function test_cancel_midway_restart_with_content_encoding()
+add_task(function* test_cancel_midway_restart_with_content_encoding()
 {
   mustInterruptResponses();
 
   let download = yield promiseStartDownload(httpUrl("interruptible_gzip.txt"));
 
   // The first time, cancel the download midway.
   let deferCancel = Promise.defer();
   let onchange = function () {
@@ -1538,17 +1568,17 @@ add_task(function test_cancel_midway_res
   do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
 
   yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
 });
 
 /**
  * Download with parental controls enabled.
  */
-add_task(function test_blocked_parental_controls()
+add_task(function* test_blocked_parental_controls()
 {
   function cleanup() {
     DownloadIntegration.shouldBlockInTest = false;
   }
   do_register_cleanup(cleanup);
   DownloadIntegration.shouldBlockInTest = true;
 
   let download;
@@ -1562,59 +1592,65 @@ add_task(function test_blocked_parental_
       // When testing DownloadLegacySaver, we cannot be sure whether we are
       // testing the promise returned by the "start" method or we are testing
       // the "error" property checked by promiseDownloadStopped.  This happens
       // because we don't have control over when the download is started.
       download = yield promiseStartLegacyDownload();
       yield promiseDownloadStopped(download);
     }
     do_throw("The download should have blocked.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
+      throw ex;
+    }
     do_check_true(ex.becauseBlockedByParentalControls);
     do_check_true(download.error.becauseBlockedByParentalControls);
   }
 
   // Now that the download stopped, the target file should not exist.
   do_check_false(yield OS.File.exists(download.target.path));
 
   cleanup();
 });
 
 /**
  * Test a download that will be blocked by Windows parental controls by
  * resulting in an HTTP status code of 450.
  */
-add_task(function test_blocked_parental_controls_httpstatus450()
+add_task(function* test_blocked_parental_controls_httpstatus450()
 {
   let download;
   try {
     if (!gUseLegacySaver) {
       download = yield promiseNewDownload(httpUrl("parentalblocked.zip"));
       yield download.start();
     }
     else {
       download = yield promiseStartLegacyDownload(httpUrl("parentalblocked.zip"));
       yield promiseDownloadStopped(download);
     }
     do_throw("The download should have blocked.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
+      throw ex;
+    }
     do_check_true(ex.becauseBlockedByParentalControls);
     do_check_true(download.error.becauseBlockedByParentalControls);
     do_check_true(download.stopped);
   }
 
   do_check_false(yield OS.File.exists(download.target.path));
 });
 
 /**
  * Check that DownloadCopySaver can always retrieve the hash.
  * DownloadLegacySaver can only retrieve the hash when
  * nsIExternalHelperAppService is invoked.
  */
-add_task(function test_getSha256Hash()
+add_task(function* test_getSha256Hash()
 {
   if (!gUseLegacySaver) {
     let download = yield promiseStartDownload(httpUrl("source.txt"));
     yield promiseDownloadStopped(download);
     do_check_true(download.stopped);
     do_check_eq(32, download.saver.getSha256Hash().length);
   }
 });
@@ -1653,34 +1689,37 @@ var promiseBlockedDownload = Task.async(
     } else {
       download = yield promiseNewDownload();
       yield download.start();
       do_throw("The download should have blocked.");
     }
 
     yield promiseDownloadStopped(download);
     do_throw("The download should have blocked.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
+      throw ex;
+    }
     do_check_true(ex.becauseBlockedByReputationCheck);
     do_check_true(download.error.becauseBlockedByReputationCheck);
   }
 
   do_check_true(download.stopped);
   do_check_false(download.succeeded);
   do_check_false(yield OS.File.exists(download.target.path));
 
   cleanup();
   return download;
 });
 
 /**
  * Checks that application reputation blocks the download and the target file
  * does not exist.
  */
-add_task(function test_blocked_applicationReputation()
+add_task(function* test_blocked_applicationReputation()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: false,
     keepBlockedData: false,
   });
 
   // Now that the download is blocked, the target file should not exist.
   do_check_false(yield OS.File.exists(download.target.path));
@@ -1690,17 +1729,17 @@ add_task(function test_blocked_applicati
   // There should also be no blocked data in this case
   do_check_false(download.hasBlockedData);
 });
 
 /**
  * Checks that application reputation blocks the download but maintains the
  * blocked data, which will be deleted when the block is confirmed.
  */
-add_task(function test_blocked_applicationReputation_confirmBlock()
+add_task(function* test_blocked_applicationReputation_confirmBlock()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: true,
     keepBlockedData: true,
   });
 
   do_check_true(download.hasBlockedData);
   do_check_true(yield OS.File.exists(download.target.partFilePath));
@@ -1717,17 +1756,17 @@ add_task(function test_blocked_applicati
   do_check_false(download.target.exists);
   do_check_eq(download.target.size, 0);
 });
 
 /**
  * Checks that application reputation blocks the download but maintains the
  * blocked data, which will be used to complete the download when unblocking.
  */
-add_task(function test_blocked_applicationReputation_unblock()
+add_task(function* test_blocked_applicationReputation_unblock()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: true,
     keepBlockedData: true,
   });
 
   do_check_true(download.hasBlockedData);
   do_check_true(yield OS.File.exists(download.target.partFilePath));
@@ -1747,17 +1786,17 @@ add_task(function test_blocked_applicati
   do_check_true(download.error instanceof Downloads.Error);
   do_check_true(download.error.becauseBlocked);
   do_check_true(download.error.becauseBlockedByReputationCheck);
 });
 
 /**
  * Check that calling cancel on a blocked download will not cause errors
  */
-add_task(function test_blocked_applicationReputation_cancel()
+add_task(function* test_blocked_applicationReputation_cancel()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: true,
     keepBlockedData: true,
   });
 
   // This call should succeed on a blocked download.
   yield download.cancel();
@@ -1768,17 +1807,17 @@ add_task(function test_blocked_applicati
   do_check_true(download.stopped);
   do_check_false(download.succeeded);
   do_check_true(download.hasBlockedData);
 });
 
 /**
  * Checks that unblock and confirmBlock cannot race on a blocked download
  */
-add_task(function test_blocked_applicationReputation_decisionRace()
+add_task(function* test_blocked_applicationReputation_decisionRace()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: true,
     keepBlockedData: true,
   });
 
   let unblockPromise = download.unblock();
   let confirmBlockPromise = download.confirmBlock();
@@ -1821,17 +1860,17 @@ add_task(function test_blocked_applicati
   do_check_false(download.target.exists);
   do_check_eq(download.target.size, 0);
 });
 
 /**
  * Checks that unblocking a blocked download fails if the blocked data has been
  * removed.
  */
-add_task(function test_blocked_applicationReputation_unblock()
+add_task(function* test_blocked_applicationReputation_unblock()
 {
   let download = yield promiseBlockedDownload({
     keepPartialData: true,
     keepBlockedData: true,
   });
 
   do_check_true(download.hasBlockedData);
   do_check_true(yield OS.File.exists(download.target.partFilePath));
@@ -1851,30 +1890,33 @@ add_task(function test_blocked_applicati
   do_check_false(download.succeeded);
   do_check_false(download.target.exists);
   do_check_eq(download.target.size, 0);
 });
 
 /**
  * download.showContainingDirectory() action
  */
-add_task(function test_showContainingDirectory() {
+add_task(function* test_showContainingDirectory() {
   DownloadIntegration._deferTestShowDir = Promise.defer();
 
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
 
   let download = yield Downloads.createDownload({
     source: { url: httpUrl("source.txt") },
     target: ""
   });
 
   try {
     yield download.showContainingDirectory();
     do_throw("Should have failed because of an invalid path.");
-  } catch (ex if ex instanceof Components.Exception) {
+  } catch (ex) {
+    if (!(ex instanceof Components.Exception)) {
+      throw ex;
+    }
     // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
     // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
     let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
                       ex.result == Cr.NS_ERROR_FAILURE;
     do_check_true(validResult);
   }
 
   download = yield Downloads.createDownload({
@@ -1887,17 +1929,17 @@ add_task(function test_showContainingDir
   download.showContainingDirectory();
   let result = yield DownloadIntegration._deferTestShowDir.promise;
   do_check_eq(result, "success");
 });
 
 /**
  * download.launch() action
  */
-add_task(function test_launch() {
+add_task(function* test_launch() {
   let customLauncher = getTempFile("app-launcher");
 
   // Test both with and without setting a custom application.
   for (let launcherPath of [null, customLauncher.path]) {
     let download;
     if (!gUseLegacySaver) {
       // When testing DownloadCopySaver, we have control over the download, thus
       // we can test that file is not launched if download.succeeded is not set.
@@ -1945,43 +1987,46 @@ add_task(function test_launch() {
                           .executable.equals(customLauncher));
     }
   }
 });
 
 /**
  * Test passing an invalid path as the launcherPath property.
  */
-add_task(function test_launcherPath_invalid() {
+add_task(function* test_launcherPath_invalid() {
   let download = yield Downloads.createDownload({
     source: { url: httpUrl("source.txt") },
     target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
     launcherPath: " "
   });
 
   DownloadIntegration._deferTestOpenFile = Promise.defer();
   yield download.start();
   try {
     download.launch();
     result = yield DownloadIntegration._deferTestOpenFile.promise;
     do_throw("Can't launch file with invalid custom launcher")
-  } catch (ex if ex instanceof Components.Exception) {
+  } catch (ex) {
+    if (!(ex instanceof Components.Exception)) {
+      throw ex;
+    }
     // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
     // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
     let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
                       ex.result == Cr.NS_ERROR_FAILURE;
     do_check_true(validResult);
   }
 });
 
 /**
  * Tests that download.launch() is automatically called after
  * the download finishes if download.launchWhenSucceeded = true
  */
-add_task(function test_launchWhenSucceeded() {
+add_task(function* test_launchWhenSucceeded() {
   let customLauncher = getTempFile("app-launcher");
 
   // Test both with and without setting a custom application.
   for (let launcherPath of [null, customLauncher.path]) {
     DownloadIntegration._deferTestOpenFile = Promise.defer();
 
     if (!gUseLegacySaver) {
       let download = yield Downloads.createDownload({
@@ -2013,28 +2058,28 @@ add_task(function test_launchWhenSucceed
                           .executable.equals(customLauncher));
     }
   }
 });
 
 /**
  * Tests that the proper content type is set for a normal download.
  */
-add_task(function test_contentType() {
+add_task(function* test_contentType() {
   let download = yield promiseStartDownload(httpUrl("source.txt"));
   yield promiseDownloadStopped(download);
 
   do_check_eq("text/plain", download.contentType);
 });
 
 /**
  * Tests that the serialization/deserialization of the startTime Date
  * object works correctly.
  */
-add_task(function test_toSerializable_startTime()
+add_task(function* test_toSerializable_startTime()
 {
   let download1 = yield promiseStartDownload(httpUrl("source.txt"));
   yield promiseDownloadStopped(download1);
 
   let serializable = download1.toSerializable();
   let reserialized = JSON.parse(JSON.stringify(serializable));
 
   let download2 = yield Downloads.createDownload(reserialized);
@@ -2044,17 +2089,17 @@ add_task(function test_toSerializable_st
   do_check_eq(download1.startTime.toJSON(), download2.startTime.toJSON());
 });
 
 /**
  * This test will call the platform specific operations within
  * DownloadPlatform::DownloadDone. While there is no test to verify the
  * specific behaviours, this at least ensures that there is no error or crash.
  */
-add_task(function test_platform_integration()
+add_task(function* test_platform_integration()
 {
   let downloadFiles = [];
   let oldDeviceStorageEnabled = false;
   try {
      oldDeviceStorageEnabled = Services.prefs.getBoolPref("device.storage.enabled");
   } catch (e) {
     // This happens if the pref doesn't exist.
   }
@@ -2115,17 +2160,17 @@ add_task(function test_platform_integrat
 
     yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
   }
 });
 
 /**
  * Checks that downloads are added to browsing history when they start.
  */
-add_task(function test_history()
+add_task(function* test_history()
 {
   mustInterruptResponses();
 
   // We will wait for the visit to be notified during the download.
   yield PlacesTestUtils.clearHistory();
   let promiseVisit = promiseWaitForVisit(httpUrl("interruptible.txt"));
 
   // Start a download that is not allowed to finish yet.
@@ -2145,17 +2190,17 @@ add_task(function test_history()
   // The restart should not have added a new history visit.
   do_check_false(yield promiseIsURIVisited(httpUrl("interruptible.txt")));
 });
 
 /**
  * Checks that downloads started by nsIHelperAppService are added to the
  * browsing history when they start.
  */
-add_task(function test_history_tryToKeepPartialData()
+add_task(function* test_history_tryToKeepPartialData()
 {
   // We will wait for the visit to be notified during the download.
   yield PlacesTestUtils.clearHistory();
   let promiseVisit =
       promiseWaitForVisit(httpUrl("interruptible_resumable.txt"));
 
   // Start a download that is not allowed to finish yet.
   let beforeStartTimeMs = Date.now();
@@ -2174,17 +2219,17 @@ add_task(function test_history_tryToKeep
   continueResponses();
   yield promiseDownloadStopped(download);
 });
 
 /**
  * Tests that the temp download files are removed on exit and exiting private
  * mode after they have been launched.
  */
-add_task(function test_launchWhenSucceeded_deleteTempFileOnExit() {
+add_task(function* test_launchWhenSucceeded_deleteTempFileOnExit() {
   const kDeleteTempFileOnExit = "browser.helperApps.deleteTempFileOnExit";
 
   let customLauncherPath = getTempFile("app-launcher").path;
   let autoDeleteTargetPathOne = getTempFile(TEST_TARGET_FILE_NAME).path;
   let autoDeleteTargetPathTwo = getTempFile(TEST_TARGET_FILE_NAME).path;
   let noAutoDeleteTargetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
 
   let autoDeleteDownloadOne = yield Downloads.createDownload({
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -527,17 +527,17 @@ function promiseNewList(aIsPrivate)
  *        String containing the octets that are expected in the file.
  *
  * @return {Promise}
  * @resolves When the operation completes.
  * @rejects Never.
  */
 function promiseVerifyContents(aPath, aExpectedContents)
 {
-  return Task.spawn(function() {
+  return Task.spawn(function* () {
     let file = new FileUtils.File(aPath);
 
     if (!(yield OS.File.exists(aPath))) {
       do_throw("File does not exist: " + aPath);
     }
 
     if ((yield OS.File.stat(aPath)).size == 0) {
       do_throw("File is empty: " + aPath);
--- a/toolkit/components/jsdownloads/test/unit/tail.js
+++ b/toolkit/components/jsdownloads/test/unit/tail.js
@@ -7,17 +7,17 @@
  * Provides infrastructure for automated download components tests.
  */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Termination functions common to all tests
 
-add_task(function test_common_terminate()
+add_task(function* test_common_terminate()
 {
   // Ensure all the pending HTTP requests have a chance to finish.
   continueResponses();
 
   // Stop the HTTP server.  We must do this inside a task in "tail.js" until the
   // xpcshell testing framework supports asynchronous termination functions.
   let deferred = Promise.defer();
   gHttpServer.stop(deferred.resolve);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
@@ -61,17 +61,17 @@ var gDownloadsRowNonImportable;
  * @param aSchemaVersion
  *        Number with the version of the database schema to set.
  *
  * @return {Promise}
  * @resolves The open connection to the database.
  * @rejects If an error occurred during the database creation.
  */
 function promiseEmptyDatabaseConnection({aPath, aSchemaVersion}) {
-  return Task.spawn(function () {
+  return Task.spawn(function* () {
     let connection = yield Sqlite.openConnection({ path: aPath });
 
     yield connection.execute("CREATE TABLE moz_downloads ("
                              + "id INTEGER PRIMARY KEY,"
                              + "name TEXT,"
                              + "source TEXT,"
                              + "target TEXT,"
                              + "tempPath TEXT,"
@@ -85,17 +85,17 @@ function promiseEmptyDatabaseConnection(
                              + "mimeType TEXT,"
                              + "preferredApplication TEXT,"
                              + "preferredAction INTEGER NOT NULL DEFAULT 0,"
                              + "autoResume INTEGER NOT NULL DEFAULT 0,"
                              + "guid TEXT)");
 
     yield connection.setSchemaVersion(aSchemaVersion);
 
-    throw new Task.Result(connection);
+    return connection;
   });
 }
 
 /**
  * Inserts a new entry in the database with the given columns' values.
  *
  * @param aConnection
  *        The database connection.
@@ -260,17 +260,17 @@ function getStartTime(aOffset) {
  *        with extra properties describing expected values that are not
  *        explictly part of the database.
  *
  * @return {Promise}
  * @resolves When the operation completes
  * @rejects Never
  */
 function checkDownload(aDownload, aDownloadRow) {
-  return Task.spawn(function() {
+  return Task.spawn(function*() {
     do_check_eq(aDownload.source.url, aDownloadRow.source);
     do_check_eq(aDownload.source.referrer, aDownloadRow.referrer);
 
     do_check_eq(aDownload.target.path,
                 NetUtil.newURI(aDownloadRow.target)
                        .QueryInterface(Ci.nsIFileURL).file.path);
 
     do_check_eq(aDownload.target.partFilePath, aDownloadRow.tempPath);
@@ -324,17 +324,17 @@ function checkDownload(aDownload, aDownl
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Preparation tasks
 
 /**
  * Prepares the list of downloads to be added to the database that should
  * be imported by the import procedure.
  */
-add_task(function prepareDownloadsToImport() {
+add_task(function* prepareDownloadsToImport() {
 
   let sourceUrl = httpUrl("source.txt");
   let sourceEntityId = yield promiseEntityID(sourceUrl);
 
   gDownloadsRowToImport = [
     // Paused download with autoResume and a partial file. By
     // setting the correct entityID the download can resume from
     // where it stopped, and to test that this works properly we
@@ -530,17 +530,17 @@ add_task(function prepareDownloadsToImpo
     },
   ];
 });
 
 /**
  * Prepares the list of downloads to be added to the database that should
  * *not* be imported by the import procedure.
  */
-add_task(function prepareNonImportableDownloads()
+add_task(function* prepareNonImportableDownloads()
 {
   gDownloadsRowNonImportable = [
     // Download with no source (should never happen in normal circumstances).
     {
       source: "",
       target: "nonimportable1.txt",
       tempPath: "",
       startTime: getStartTime(1),
@@ -655,17 +655,17 @@ add_task(function prepareNonImportableDo
 ////////////////////////////////////////////////////////////////////////////////
 //// Test
 
 /**
  * Creates a temporary Sqlite database with download data and perform an
  * import of that data to the new Downloads API to verify that the import
  * worked correctly.
  */
-add_task(function test_downloadImport()
+add_task(function* test_downloadImport()
 {
   let connection = null;
   let downloadsSqlite = getTempFile("downloads.sqlite").path;
 
   try {
     // Set up the database.
     connection = yield promiseEmptyDatabaseConnection({
       aPath: downloadsSqlite,
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
@@ -63,17 +63,17 @@ XPCOMUtils.defineLazyGetter(this, "gStri
   return Services.strings.
     createBundle("chrome://mozapps/locale/downloads/downloads.properties");
 });
 
 /**
  * Tests that the getSystemDownloadsDirectory returns a valid download
  * directory string path.
  */
-add_task(function test_getSystemDownloadsDirectory()
+add_task(function* test_getSystemDownloadsDirectory()
 {
   // Enable test mode for the getSystemDownloadsDirectory method to return
   // temp directory instead so we can check whether the desired directory
   // is created or not.
   DownloadIntegration.testMode = true;
   function cleanup() {
     DownloadIntegration.testMode = false;
   }
@@ -113,17 +113,17 @@ add_task(function test_getSystemDownload
   let downloadDirAfter = yield DownloadIntegration.getSystemDownloadsDirectory();
   do_check_neq(downloadDirBefore, downloadDirAfter);
 });
 
 /**
  * Tests that the getPreferredDownloadsDirectory returns a valid download
  * directory string path.
  */
-add_task(function test_getPreferredDownloadsDirectory()
+add_task(function* test_getPreferredDownloadsDirectory()
 {
   let folderListPrefName = "browser.download.folderList";
   let dirPrefName = "browser.download.dir";
   function cleanup() {
     Services.prefs.clearUserPref(folderListPrefName);
     Services.prefs.clearUserPref(dirPrefName);
   }
   do_register_cleanup(cleanup);
@@ -176,17 +176,17 @@ add_task(function test_getPreferredDownl
 
   cleanup();
 });
 
 /**
  * Tests that the getTemporaryDownloadsDirectory returns a valid download
  * directory string path.
  */
-add_task(function test_getTemporaryDownloadsDirectory()
+add_task(function* test_getTemporaryDownloadsDirectory()
 {
   let downloadDir = yield DownloadIntegration.getTemporaryDownloadsDirectory();
   do_check_neq(downloadDir, "");
 
   if ("nsILocalFileMac" in Ci) {
     let preferredDownloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
     do_check_eq(downloadDir, preferredDownloadDir);
   } else {
@@ -197,17 +197,17 @@ add_task(function test_getTemporaryDownl
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests DownloadObserver
 
 /**
  * Tests notifications prompts when observers are notified if there are public
  * and private active downloads.
  */
-add_task(function test_notifications()
+add_task(function* test_notifications()
 {
   enableObserversTestMode();
 
   for (let isPrivate of [false, true]) {
     mustInterruptResponses();
 
     let list = yield promiseNewList(isPrivate);
     let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
@@ -237,17 +237,17 @@ add_task(function test_notifications()
     yield list.remove(download3);
   }
 });
 
 /**
  * Tests that notifications prompts observers are not notified if there are no
  * public or private active downloads.
  */
-add_task(function test_no_notifications()
+add_task(function* test_no_notifications()
 {
   enableObserversTestMode();
 
   for (let isPrivate of [false, true]) {
     let list = yield promiseNewList(isPrivate);
     let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
     let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
     download1.start();
@@ -267,17 +267,17 @@ add_task(function test_no_notifications(
     yield list.remove(download2);
   }
 });
 
 /**
  * Tests notifications prompts when observers are notified if there are public
  * and private active downloads at the same time.
  */
-add_task(function test_mix_notifications()
+add_task(function* test_mix_notifications()
 {
   enableObserversTestMode();
   mustInterruptResponses();
 
   let publicList = yield promiseNewList();
   let privateList = yield Downloads.getList(Downloads.PRIVATE);
   let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
   let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
@@ -299,31 +299,31 @@ add_task(function test_mix_notifications
   yield publicList.remove(download1);
   yield privateList.remove(download2);
 });
 
 /**
  * Tests suspending and resuming as well as going offline and then online again.
  * The downloads should stop when suspending and start again when resuming.
  */
-add_task(function test_suspend_resume()
+add_task(function* test_suspend_resume()
 {
   enableObserversTestMode();
 
   // The default wake delay is 10 seconds, so set the wake delay to be much
   // faster for these tests.
   Services.prefs.setIntPref("browser.download.manager.resumeOnWakeDelay", 5);
 
   let addDownload = function(list)
   {
-    return Task.spawn(function () {
+    return Task.spawn(function* () {
       let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
       download.start();
       list.add(download);
-      throw new Task.Result(download);
+      return download;
     });
   }
 
   let publicList = yield promiseNewList();
   let privateList = yield promiseNewList(true);
 
   let download1 = yield addDownload(publicList);
   let download2 = yield addDownload(publicList);
@@ -380,17 +380,17 @@ add_task(function test_suspend_resume()
 
   Services.prefs.clearUserPref("browser.download.manager.resumeOnWakeDelay");
 });
 
 /**
  * Tests both the downloads list and the in-progress downloads are clear when
  * private browsing observer is notified.
  */
-add_task(function test_exit_private_browsing()
+add_task(function* test_exit_private_browsing()
 {
   enableObserversTestMode();
   mustInterruptResponses();
 
   let privateList = yield promiseNewList(true);
   let download1 = yield promiseNewDownload(httpUrl("source.txt"));
   let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
   let promiseAttempt1 = download1.start();
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
@@ -66,32 +66,32 @@ function promiseExpirableDownloadVisit(a
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
  * Checks the testing mechanism used to build different download lists.
  */
-add_task(function test_construction()
+add_task(function* test_construction()
 {
   let downloadListOne = yield promiseNewList();
   let downloadListTwo = yield promiseNewList();
   let privateDownloadListOne = yield promiseNewList(true);
   let privateDownloadListTwo = yield promiseNewList(true);
 
   do_check_neq(downloadListOne, downloadListTwo);
   do_check_neq(privateDownloadListOne, privateDownloadListTwo);
   do_check_neq(downloadListOne, privateDownloadListOne);
 });
 
 /**
  * Checks the methods to add and retrieve items from the list.
  */
-add_task(function test_add_getAll()
+add_task(function* test_add_getAll()
 {
   let list = yield promiseNewList();
 
   let downloadOne = yield promiseNewDownload();
   yield list.add(downloadOne);
 
   let itemsOne = yield list.getAll();
   do_check_eq(itemsOne.length, 1);
@@ -107,17 +107,17 @@ add_task(function test_add_getAll()
 
   // The first snapshot should not have been modified.
   do_check_eq(itemsOne.length, 1);
 });
 
 /**
  * Checks the method to remove items from the list.
  */
-add_task(function test_remove()
+add_task(function* test_remove()
 {
   let list = yield promiseNewList();
 
   yield list.add(yield promiseNewDownload());
   yield list.add(yield promiseNewDownload());
 
   let items = yield list.getAll();
   yield list.remove(items[0]);
@@ -129,17 +129,17 @@ add_task(function test_remove()
   do_check_eq(items.length, 1);
 });
 
 /**
  * Tests that the "add", "remove", and "getAll" methods on the global
  * DownloadCombinedList object combine the contents of the global DownloadList
  * objects for public and private downloads.
  */
-add_task(function test_DownloadCombinedList_add_remove_getAll()
+add_task(function* test_DownloadCombinedList_add_remove_getAll()
 {
   let publicList = yield promiseNewList();
   let privateList = yield Downloads.getList(Downloads.PRIVATE);
   let combinedList = yield Downloads.getList(Downloads.ALL);
 
   let publicDownload = yield promiseNewDownload();
   let privateDownload = yield Downloads.createDownload({
     source: { url: httpUrl("source.txt"), isPrivate: true },
@@ -169,17 +169,17 @@ add_task(function test_DownloadCombinedL
   do_check_eq((yield combinedList.getAll()).length, 0);
 });
 
 /**
  * Checks that views receive the download add and remove notifications, and that
  * adding and removing views works as expected, both for a normal and a combined
  * list.
  */
-add_task(function test_notifications_add_remove()
+add_task(function* test_notifications_add_remove()
 {
   for (let isCombined of [false, true]) {
     // Force creating a new list for both the public and combined cases.
     let list = yield promiseNewList();
     if (isCombined) {
       list = yield Downloads.getList(Downloads.ALL);
     }
 
@@ -234,17 +234,17 @@ add_task(function test_notifications_add
     do_check_eq(addNotifications, 3);
   }
 });
 
 /**
  * Checks that views receive the download change notifications, both for a
  * normal and a combined list.
  */
-add_task(function test_notifications_change()
+add_task(function* test_notifications_change()
 {
   for (let isCombined of [false, true]) {
     // Force creating a new list for both the public and combined cases.
     let list = yield promiseNewList();
     if (isCombined) {
       list = yield Downloads.getList(Downloads.ALL);
     }
 
@@ -273,17 +273,17 @@ add_task(function test_notifications_cha
     yield downloadTwo.start();
     do_check_false(receivedOnDownloadChanged);
   }
 });
 
 /**
  * Checks that the reference to "this" is correct in the view callbacks.
  */
-add_task(function test_notifications_this()
+add_task(function* test_notifications_this()
 {
   let list = yield promiseNewList();
 
   // Check that we receive change notifications.
   let receivedOnDownloadAdded = false;
   let receivedOnDownloadChanged = false;
   let receivedOnDownloadRemoved = false;
   let view = {
@@ -314,17 +314,17 @@ add_task(function test_notifications_thi
   do_check_true(receivedOnDownloadAdded);
   do_check_true(receivedOnDownloadChanged);
   do_check_true(receivedOnDownloadRemoved);
 });
 
 /**
  * Checks that download is removed on history expiration.
  */
-add_task(function test_history_expiration()
+add_task(function* test_history_expiration()
 {
   mustInterruptResponses();
 
   function cleanup() {
     Services.prefs.clearUserPref("places.history.expiration.max_pages");
   }
   do_register_cleanup(cleanup);
 
@@ -369,17 +369,17 @@ add_task(function test_history_expiratio
   yield deferred.promise;
 
   cleanup();
 });
 
 /**
  * Checks all downloads are removed after clearing history.
  */
-add_task(function test_history_clear()
+add_task(function* test_history_clear()
 {
   let list = yield promiseNewList();
   let downloadOne = yield promiseNewDownload();
   let downloadTwo = yield promiseNewDownload();
   yield list.add(downloadOne);
   yield list.add(downloadTwo);
 
   let deferred = Promise.defer();
@@ -401,17 +401,17 @@ add_task(function test_history_clear()
   // Wait for the removal notifications that may still be pending.
   yield deferred.promise;
 });
 
 /**
  * Tests the removeFinished method to ensure that it only removes
  * finished downloads.
  */
-add_task(function test_removeFinished()
+add_task(function* test_removeFinished()
 {
   let list = yield promiseNewList();
   let downloadOne = yield promiseNewDownload();
   let downloadTwo = yield promiseNewDownload();
   let downloadThree = yield promiseNewDownload();
   let downloadFour = yield promiseNewDownload();
   yield list.add(downloadOne);
   yield list.add(downloadTwo);
@@ -447,17 +447,17 @@ add_task(function test_removeFinished()
   let downloads = yield list.getAll()
   do_check_eq(downloads.length, 1);
 });
 
 /**
  * Tests the global DownloadSummary objects for the public, private, and
  * combined download lists.
  */
-add_task(function test_DownloadSummary()
+add_task(function* test_DownloadSummary()
 {
   mustInterruptResponses();
 
   let publicList = yield promiseNewList();
   let privateList = yield Downloads.getList(Downloads.PRIVATE);
 
   let publicSummary = yield Downloads.getSummary(Downloads.PUBLIC);
   let privateSummary = yield Downloads.getSummary(Downloads.PRIVATE);
@@ -541,17 +541,17 @@ add_task(function test_DownloadSummary()
   do_check_eq(combinedSummary.progressCurrentBytes, 0);
 });
 
 /**
  * Checks that views receive the summary change notification.  This is tested on
  * the combined summary when adding a public download, as we assume that if we
  * pass the test in this case we will also pass it in the others.
  */
-add_task(function test_DownloadSummary_notifications()
+add_task(function* test_DownloadSummary_notifications()
 {
   let list = yield promiseNewList();
   let summary = yield Downloads.getSummary(Downloads.ALL);
 
   let download = yield promiseNewDownload();
   yield list.add(download);
 
   // Check that we receive change notifications.
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
@@ -39,17 +39,17 @@ function promiseNewListAndStore(aStorePa
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
  * Saves downloads to a file, then reloads them.
  */
-add_task(function test_save_reload()
+add_task(function* test_save_reload()
 {
   let [listForSave, storeForSave] = yield promiseNewListAndStore();
   let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
                                                  storeForSave.path);
 
   listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
   listForSave.add(yield Downloads.createDownload({
     source: { url: httpUrl("empty.txt"),
@@ -96,17 +96,17 @@ add_task(function test_save_reload()
     do_check_eq(itemsForSave[i].saver.toSerializable(),
                 itemsForLoad[i].saver.toSerializable());
   }
 });
 
 /**
  * Checks that saving an empty list deletes any existing file.
  */
-add_task(function test_save_empty()
+add_task(function* test_save_empty()
 {
   let [list, store] = yield promiseNewListAndStore();
 
   let createdFile = yield OS.File.open(store.path, { create: true });
   yield createdFile.close();
 
   yield store.save();
 
@@ -114,34 +114,34 @@ add_task(function test_save_empty()
 
   // If the file does not exist, saving should not generate exceptions.
   yield store.save();
 });
 
 /**
  * Checks that loading from a missing file results in an empty list.
  */
-add_task(function test_load_empty()
+add_task(function* test_load_empty()
 {
   let [list, store] = yield promiseNewListAndStore();
 
   do_check_false(yield OS.File.exists(store.path));
 
   yield store.load();
 
   let items = yield list.getAll();
   do_check_eq(items.length, 0);
 });
 
 /**
  * Loads downloads from a string in a predefined format.  The purpose of this
  * test is to verify that the JSON format used in previous versions can be
  * loaded, assuming the file is reloaded on the same platform.
  */
-add_task(function test_load_string_predefined()
+add_task(function* test_load_string_predefined()
 {
   let [list, store] = yield promiseNewListAndStore();
 
   // The platform-dependent file name should be generated dynamically.
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   let filePathLiteral = JSON.stringify(targetPath);
   let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
   let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
@@ -169,17 +169,17 @@ add_task(function test_load_string_prede
   do_check_eq(items[1].source.url, httpUrl("empty.txt"));
   do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
   do_check_eq(items[1].target.path, targetPath);
 });
 
 /**
  * Loads downloads from a well-formed JSON string containing unrecognized data.
  */
-add_task(function test_load_string_unrecognized()
+add_task(function* test_load_string_unrecognized()
 {
   let [list, store] = yield promiseNewListAndStore();
 
   // The platform-dependent file name should be generated dynamically.
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   let filePathLiteral = JSON.stringify(targetPath);
   let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
 
@@ -201,43 +201,46 @@ add_task(function test_load_string_unrec
 
   do_check_eq(items[0].source.url, httpUrl("source.txt"));
   do_check_eq(items[0].target.path, targetPath);
 });
 
 /**
  * Loads downloads from a malformed JSON string.
  */
-add_task(function test_load_string_malformed()
+add_task(function* test_load_string_malformed()
 {
   let [list, store] = yield promiseNewListAndStore();
 
   let string = "{\"list\":[{\"source\":null,\"target\":null}," +
                 "{\"source\":{\"url\":\"about:blank\"}}}";
 
   yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
                             { tmpPath: store.path + ".tmp" });
 
   try {
     yield store.load();
     do_throw("Exception expected when JSON data is malformed.");
-  } catch (ex if ex.name == "SyntaxError") {
+  } catch (ex) {
+    if (ex.name != "SyntaxError") {
+      throw ex;
+    }
     do_print("The expected SyntaxError exception was thrown.");
   }
 
   let items = yield list.getAll();
 
   do_check_eq(items.length, 0);
 });
 
 /**
  * Saves downloads with unknown properties to a file and then reloads
  * them to ensure that these properties are preserved.
  */
-add_task(function test_save_reload_unknownProperties()
+add_task(function* test_save_reload_unknownProperties()
 {
   let [listForSave, storeForSave] = yield promiseNewListAndStore();
   let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
                                                  storeForSave.path);
 
   let download1 = yield promiseNewDownload(httpUrl("source.txt"));
   // startTime should be ignored as it is a known property, and error
   // is ignored by serialization
--- a/toolkit/components/jsdownloads/test/unit/test_Downloads.js
+++ b/toolkit/components/jsdownloads/test/unit/test_Downloads.js
@@ -11,43 +11,43 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
  * Tests that the createDownload function exists and can be called.  More
  * detailed tests are implemented separately for the DownloadCore module.
  */
-add_task(function test_createDownload()
+add_task(function* test_createDownload()
 {
   // Creates a simple Download object without starting the download.
   yield Downloads.createDownload({
     source: { url: "about:blank" },
     target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
     saver: { type: "copy" },
   });
 });
 
 /**
  * Tests createDownload for private download.
  */
-add_task(function test_createDownload_private()
+add_task(function* test_createDownload_private()
 {
   let download = yield Downloads.createDownload({
     source: { url: "about:blank", isPrivate: true },
     target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
     saver: { type: "copy" }
   });
   do_check_true(download.source.isPrivate);
 });
 
 /**
  * Tests createDownload for normal (public) download.
  */
-add_task(function test_createDownload_public()
+add_task(function* test_createDownload_public()
 {
   let tempPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   let download = yield Downloads.createDownload({
     source: { url: "about:blank", isPrivate: false },
     target: { path: tempPath },
     saver: { type: "copy" }
   });
   do_check_false(download.source.isPrivate);
@@ -58,62 +58,66 @@ add_task(function test_createDownload_pu
     saver: { type: "copy" }
   });
   do_check_false(download.source.isPrivate);
 });
 
 /**
  * Tests createDownload for a pdf saver throws if only given a url.
  */
-add_task(function test_createDownload_pdf()
+add_task(function* test_createDownload_pdf()
 {
   let download = yield Downloads.createDownload({
     source: { url: "about:blank" },
     target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
     saver: { type: "pdf" },
   });
 
   try {
     yield download.start();
     do_throw("The download should have failed.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) { }
+  } catch (ex) {
+    if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
+      throw ex;
+    }
+  }
 
   do_check_false(download.succeeded);
   do_check_true(download.stopped);
   do_check_false(download.canceled);
   do_check_true(download.error !== null);
   do_check_true(download.error.becauseSourceFailed);
   do_check_false(download.error.becauseTargetFailed);
   do_check_false(yield OS.File.exists(download.target.path));
 });
 
 /**
  * Tests "fetch" with nsIURI and nsIFile as arguments.
  */
-add_task(function test_fetch_uri_file_arguments()
+add_task(function* test_fetch_uri_file_arguments()
 {
   let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
   yield Downloads.fetch(NetUtil.newURI(httpUrl("source.txt")), targetFile);
   yield promiseVerifyContents(targetFile.path, TEST_DATA_SHORT);
 });
 
 /**
  * Tests "fetch" with DownloadSource and DownloadTarget as arguments.
  */
-add_task(function test_fetch_object_arguments()
+add_task(function* test_fetch_object_arguments()
 {
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   yield Downloads.fetch({ url: httpUrl("source.txt") }, { path: targetPath });
   yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
 });
 
 /**
  * Tests "fetch" with string arguments.
  */
-add_task(function test_fetch_string_arguments()
+add_task(function* test_fetch_string_arguments()
 {
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   yield Downloads.fetch(httpUrl("source.txt"), targetPath);
   yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
 
   targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
   yield Downloads.fetch(new String(httpUrl("source.txt")),
                         new String(targetPath));
@@ -121,17 +125,17 @@ add_task(function test_fetch_string_argu
 });
 
 /**
  * Tests that the getList function returns the same list when called multiple
  * times with the same argument, but returns different lists when called with
  * different arguments.  More detailed tests are implemented separately for the
  * DownloadList module.
  */
-add_task(function test_getList()
+add_task(function* test_getList()
 {
   let publicListOne = yield Downloads.getList(Downloads.PUBLIC);
   let privateListOne = yield Downloads.getList(Downloads.PRIVATE);
 
   let publicListTwo = yield Downloads.getList(Downloads.PUBLIC);
   let privateListTwo = yield Downloads.getList(Downloads.PRIVATE);
 
   do_check_eq(publicListOne, publicListTwo);
@@ -141,17 +145,17 @@ add_task(function test_getList()
 });
 
 /**
  * Tests that the getSummary function returns the same summary when called
  * multiple times with the same argument, but returns different summaries when
  * called with different arguments.  More detailed tests are implemented
  * separately for the DownloadSummary object in the DownloadList module.
  */
-add_task(function test_getSummary()
+add_task(function* test_getSummary()
 {
   let publicSummaryOne = yield Downloads.getSummary(Downloads.PUBLIC);
   let privateSummaryOne = yield Downloads.getSummary(Downloads.PRIVATE);
 
   let publicSummaryTwo = yield Downloads.getSummary(Downloads.PUBLIC);
   let privateSummaryTwo = yield Downloads.getSummary(Downloads.PRIVATE);
 
   do_check_eq(publicSummaryOne, publicSummaryTwo);
@@ -159,37 +163,37 @@ add_task(function test_getSummary()
 
   do_check_neq(publicSummaryOne, privateSummaryOne);
 });
 
 /**
  * Tests that the getSystemDownloadsDirectory returns a non-empty download
  * directory string.
  */
-add_task(function test_getSystemDownloadsDirectory()
+add_task(function* test_getSystemDownloadsDirectory()
 {
   let downloadDir = yield Downloads.getSystemDownloadsDirectory();
   do_check_neq(downloadDir, "");
 });
 
 /**
  * Tests that the getPreferredDownloadsDirectory returns a non-empty download
  * directory string.
  */
-add_task(function test_getPreferredDownloadsDirectory()
+add_task(function* test_getPreferredDownloadsDirectory()
 {
   let downloadDir = yield Downloads.getPreferredDownloadsDirectory();
   do_check_neq(downloadDir, "");
 });
 
 /**
  * Tests that the getTemporaryDownloadsDirectory returns a non-empty download
  * directory string.
  */
-add_task(function test_getTemporaryDownloadsDirectory()
+add_task(function* test_getTemporaryDownloadsDirectory()
 {
   let downloadDir = yield Downloads.getTemporaryDownloadsDirectory();
   do_check_neq(downloadDir, "");
 });
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Termination
 
--- a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
+++ b/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
@@ -4,17 +4,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /*
  * The temporary directory downloads saves to, should be only readable
  * for the current user.
  */
-add_task(function test_private_temp() {
+add_task(function* test_private_temp() {
 
   let download = yield promiseStartExternalHelperAppServiceDownload(
                                                          httpUrl("empty.txt"));
 
   yield promiseDownloadStopped(download);
 
   var targetFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
   targetFile.initWithPath(download.target.path);
--- a/toolkit/mozapps/downloads/DownloadTaskbarProgress.jsm
+++ b/toolkit/mozapps/downloads/DownloadTaskbarProgress.jsm
@@ -12,16 +12,17 @@ this.EXPORTED_SYMBOLS = [
 //// Constants
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
 const kTaskbarIDWin = "@mozilla.org/windows-taskbar;1";
 const kTaskbarIDMac = "@mozilla.org/widget/macdocksupport;1";
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadTaskbarProgress Object
@@ -174,61 +175,60 @@ var DownloadTaskbarProgressUpdater =
    *
    * @param aWindow
    *        The window to set as active.
    * @param aIsDownloadWindow
    *        Whether this window is a download window.
    */
   _setActiveWindow: function DTPU_setActiveWindow(aWindow, aIsDownloadWindow)
   {
-#ifdef XP_WIN
-    // Clear out the taskbar for the old active window. (If there was no active
-    // window, this is a no-op.)
-    this._clearTaskbar();
+    if (AppConstants.platform == "win") {
+      // Clear out the taskbar for the old active window. (If there was no active
+      // window, this is a no-op.)
+      this._clearTaskbar();
 
-    this._activeWindowIsDownloadWindow = aIsDownloadWindow;
-    if (aWindow) {
-      // Get the taskbar progress for this window
-      let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
-                       getInterface(Ci.nsIWebNavigation).
-                       QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
-                       QueryInterface(Ci.nsIInterfaceRequestor).
-                       getInterface(Ci.nsIXULWindow).docShell;
-      let taskbarProgress = this._taskbar.getTaskbarProgress(docShell);
-      this._activeTaskbarProgress = taskbarProgress;
+      this._activeWindowIsDownloadWindow = aIsDownloadWindow;
+      if (aWindow) {
+        // Get the taskbar progress for this window
+        let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                         getInterface(Ci.nsIWebNavigation).
+                         QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
+                         QueryInterface(Ci.nsIInterfaceRequestor).
+                         getInterface(Ci.nsIXULWindow).docShell;
+        let taskbarProgress = this._taskbar.getTaskbarProgress(docShell);
+        this._activeTaskbarProgress = taskbarProgress;
 
-      this._updateTaskbar();
-      // _onActiveWindowUnload is idempotent, so we don't need to check whether
-      // we've already set this before or not.
-      aWindow.addEventListener("unload", function () {
-        DownloadTaskbarProgressUpdater._onActiveWindowUnload(taskbarProgress);
-      }, false);
+        this._updateTaskbar();
+        // _onActiveWindowUnload is idempotent, so we don't need to check whether
+        // we've already set this before or not.
+        aWindow.addEventListener("unload", function () {
+          DownloadTaskbarProgressUpdater._onActiveWindowUnload(taskbarProgress);
+        }, false);
+      }
+      else {
+        this._activeTaskbarProgress = null;
+      }
     }
-    else {
-      this._activeTaskbarProgress = null;
-    }
-#endif
   },
 
   /// Current state displayed on the active window's taskbar item
   _taskbarState: null,
   _totalSize: 0,
   _totalTransferred: 0,
 
   _shouldSetState: function DTPU_shouldSetState()
   {
-#ifdef XP_WIN
-    // If the active window is not the download manager window, set the state
-    // only if it is normal or indeterminate.
-    return this._activeWindowIsDownloadWindow ||
-           (this._taskbarState == Ci.nsITaskbarProgress.STATE_NORMAL ||
-            this._taskbarState == Ci.nsITaskbarProgress.STATE_INDETERMINATE);
-#else
+    if (AppConstants.platform == "win") {
+      // If the active window is not the download manager window, set the state
+      // only if it is normal or indeterminate.
+      return this._activeWindowIsDownloadWindow ||
+             (this._taskbarState == Ci.nsITaskbarProgress.STATE_NORMAL ||
+              this._taskbarState == Ci.nsITaskbarProgress.STATE_INDETERMINATE);
+    }
     return true;
-#endif
   },
 
   /**
    * Update the active window's taskbar indicator with the current state. There
    * are two cases here:
    * 1. If the active window is the download window, then we always update
    *    the taskbar indicator.
    * 2. If the active window isn't the download window, then we update only if
--- a/toolkit/mozapps/downloads/content/downloads.js
+++ b/toolkit/mozapps/downloads/content/downloads.js
@@ -1,12 +1,11 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Globals
 
 const PREF_BDM_CLOSEWHENDONE = "browser.download.manager.closeWhenDone";
 const PREF_BDM_ALERTONEXEOPEN = "browser.download.manager.alertOnEXEOpen";
@@ -16,16 +15,17 @@ const nsLocalFile = Components.Construct
                                            "nsILocalFile", "initWithPath");
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 var gDownloadManager = Cc["@mozilla.org/download-manager;1"].getService(nsIDM);
 var gDownloadManagerUI = Cc["@mozilla.org/download-manager-ui;1"].
@@ -252,28 +252,28 @@ function openDownload(aDownload)
   if (f.isExecutable()) {
     var dontAsk = false;
     var pref = Cc["@mozilla.org/preferences-service;1"].
                getService(Ci.nsIPrefBranch);
     try {
       dontAsk = !pref.getBoolPref(PREF_BDM_ALERTONEXEOPEN);
     } catch (e) { }
 
-#ifdef XP_WIN
-    // On Vista and above, we rely on native security prompting for
-    // downloaded content unless it's disabled.
-    try {
-      var sysInfo = Cc["@mozilla.org/system-info;1"].
-                    getService(Ci.nsIPropertyBag2);
-      if (parseFloat(sysInfo.getProperty("version")) >= 6 &&
-          pref.getBoolPref(PREF_BDM_SCANWHENDONE)) {
-        dontAsk = true;
-      }
-    } catch (ex) { }
-#endif
+    if (AppConstants.platform == "win") {
+      // On Vista and above, we rely on native security prompting for
+      // downloaded content unless it's disabled.
+      try {
+        var sysInfo = Cc["@mozilla.org/system-info;1"].
+                      getService(Ci.nsIPropertyBag2);
+        if (parseFloat(sysInfo.getProperty("version")) >= 6 &&
+            pref.getBoolPref(PREF_BDM_SCANWHENDONE)) {
+          dontAsk = true;
+        }
+      } catch (ex) { }
+    }
 
     if (!dontAsk) {
       var strings = document.getElementById("downloadStrings");
       var name = aDownload.getAttribute("target");
       var message = strings.getFormattedString("fileExecutableSecurityWarning", [name, name]);
 
       let title = gStr.fileExecutableSecurityWarningTitle;
       let dontAsk = gStr.fileExecutableSecurityWarningDontAsk;
@@ -481,21 +481,20 @@ var gDownloadObserver = {
         }
 
         // Otherwise, remove a single download
         let id = aSubject.QueryInterface(Ci.nsISupportsPRUint32);
         let dl = getDownload(id.data);
         removeFromView(dl);
         break;
       case "browser-lastwindow-close-granted":
-#ifndef XP_MACOSX
-        if (gDownloadManager.activeDownloadCount == 0) {
+        if (AppConstants.platform != "macosx" &&
+            gDownloadManager.activeDownloadCount == 0) {
           setTimeout(gCloseDownloadManager, 0);
         }
-#endif
         break;
     }
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// View Context Menus
 
--- a/toolkit/mozapps/downloads/jar.mn
+++ b/toolkit/mozapps/downloads/jar.mn
@@ -2,12 +2,12 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
 % content mozapps %content/mozapps/
   content/mozapps/downloads/helperApps.js                       (content/helperApps.js)
 * content/mozapps/downloads/unknownContentType.xul              (content/unknownContentType.xul)
 * content/mozapps/downloads/downloads.xul                       (content/downloads.xul)
-* content/mozapps/downloads/downloads.js                        (content/downloads.js)
+  content/mozapps/downloads/downloads.js                        (content/downloads.js)
   content/mozapps/downloads/DownloadProgressListener.js         (content/DownloadProgressListener.js)
   content/mozapps/downloads/downloads.css                       (content/downloads.css)
   content/mozapps/downloads/download.xml                        (content/download.xml)
--- a/toolkit/mozapps/downloads/moz.build
+++ b/toolkit/mozapps/downloads/moz.build
@@ -12,16 +12,13 @@ EXTRA_COMPONENTS += [
 
 EXTRA_PP_COMPONENTS += [
     'nsHelperAppDlg.js',
 ]
 
 EXTRA_JS_MODULES += [
     'DownloadLastDir.jsm',
     'DownloadPaths.jsm',
+    'DownloadTaskbarProgress.jsm',
     'DownloadUtils.jsm',
 ]
 
-EXTRA_PP_JS_MODULES += [
-    'DownloadTaskbarProgress.jsm',
-]
-
 JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -1,18 +1,15 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/*
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-*/
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {utils: Cu, interfaces: Ci, classes: Cc, results: Cr} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "EnableDelayHelper",
                                   "resource://gre/modules/SharedPromptUtils.jsm");
 
 ///////////////////////////////////////////////////////////////////////////////
 //// Helper Functions
 
 /**
@@ -405,32 +402,32 @@ nsUnknownContentTypeDialog.prototype = {
 
     aLeafName = this.getFinalLeafName(aLeafName, aFileExt);
     aLocalFolder.append(aLeafName);
 
     // The following assignment can throw an exception, but
     // is now caught properly in the caller of validateLeafName.
     var createdFile = DownloadPaths.createNiceUniqueFile(aLocalFolder);
 
-#ifdef XP_WIN
-    let ext;
-    try {
-      // We can fail here if there's no primary extension set
-      ext = "." + this.mLauncher.MIMEInfo.primaryExtension;
-    } catch (e) { }
+    if (AppConstants.platform == "win") {
+      let ext;
+      try {
+        // We can fail here if there's no primary extension set
+        ext = "." + this.mLauncher.MIMEInfo.primaryExtension;
+      } catch (e) { }
 
-    // Append a file extension if it's an executable that doesn't have one
-    // but make sure we actually have an extension to add
-    let leaf = createdFile.leafName;
-    if (ext && leaf.slice(-ext.length) != ext && createdFile.isExecutable()) {
-      createdFile.remove(false);
-      aLocalFolder.leafName = leaf + ext;
-      createdFile = DownloadPaths.createNiceUniqueFile(aLocalFolder);
+      // Append a file extension if it's an executable that doesn't have one
+      // but make sure we actually have an extension to add
+      let leaf = createdFile.leafName;
+      if (ext && leaf.slice(-ext.length) != ext && createdFile.isExecutable()) {
+        createdFile.remove(false);
+        aLocalFolder.leafName = leaf + ext;
+        createdFile = DownloadPaths.createNiceUniqueFile(aLocalFolder);
+      }
     }
-#endif
 
     return createdFile;
   },
 
   // ---------- implementation methods ----------
 
   // initDialog:  Fill various dialog fields with initial content.
   initDialog : function() {
@@ -497,17 +494,16 @@ nsUnknownContentTypeDialog.prototype = {
       this.initAppAndSaveToDiskValues();
 
       // Initialize "always ask me" box. This should always be disabled
       // and set to true for the ambiguous type application/octet-stream.
       // We don't also check for application/x-msdownload here since we
       // want users to be able to autodownload .exe files.
       var rememberChoice = this.dialogElement("rememberChoice");
 
-#if 0
       // Just because we have a content-type of application/octet-stream
       // here doesn't actually mean that the content is of that type. Many
       // servers default to sending text/plain for file types they don't know
       // about. To account for this, the uriloader does some checking to see
       // if a file sent as text/plain contains binary characters, and if so (*)
       // it morphs the content-type into application/octet-stream so that
       // the file can be properly handled. Since this is not generic binary
       // data, rather, a data format that the system probably knows about,
@@ -517,17 +513,16 @@ nsUnknownContentTypeDialog.prototype = {
       // This is so we don't needlessly disable the "autohandle" checkbox.
 
       // commented out to close the opening brace in the if statement.
       // var mimeService = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService);
       // var type = mimeService.getTypeFromURI(this.mLauncher.source);
       // this.realMIMEInfo = mimeService.getFromTypeAndExtension(type, "");
 
       // if (type == "application/octet-stream") {
-#endif
       if (shouldntRememberChoice) {
         rememberChoice.checked = false;
         rememberChoice.disabled = true;
       }
       else {
         rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling &&
                                  this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.handleInternally;
       }
@@ -638,32 +633,31 @@ nsUnknownContentTypeDialog.prototype = {
     else {
       type.value = typeString;
     }
   },
 
   // Returns true if opening the default application makes sense.
   openWithDefaultOK: function() {
     // The checking is different on Windows...
-#ifdef XP_WIN
-    // Windows presents some special cases.
-    // We need to prevent use of "system default" when the file is
-    // executable (so the user doesn't launch nasty programs downloaded
-    // from the web), and, enable use of "system default" if it isn't
-    // executable (because we will prompt the user for the default app
-    // in that case).
+    if (AppConstants.platform == "win") {
+      // Windows presents some special cases.
+      // We need to prevent use of "system default" when the file is
+      // executable (so the user doesn't launch nasty programs downloaded
+      // from the web), and, enable use of "system default" if it isn't
+      // executable (because we will prompt the user for the default app
+      // in that case).
 
-    //  Default is Ok if the file isn't executable (and vice-versa).
-    return !this.mLauncher.targetFileIsExecutable;
-#else
+      //  Default is Ok if the file isn't executable (and vice-versa).
+      return !this.mLauncher.targetFileIsExecutable;
+    }
     // On other platforms, default is Ok if there is a default app.
     // Note that nsIMIMEInfo providers need to ensure that this holds true
     // on each platform.
     return this.mLauncher.MIMEInfo.hasDefaultHandler;
-#endif
   },
 
   // Set "default" application description field.
   initDefaultApp: function() {
     // Use description, if we can get one.
     var desc = this.mLauncher.MIMEInfo.defaultDescription;
     if (desc) {
       var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
@@ -674,21 +668,20 @@ nsUnknownContentTypeDialog.prototype = {
       // Hide the default handler item too, in case the user picks a
       // custom handler at a later date which triggers the menulist to show.
       this.dialogElement("defaultHandler").hidden = true;
     }
   },
 
   // getPath:
   getPath: function (aFile) {
-#ifdef XP_MACOSX
-    return aFile.leafName || aFile.path;
-#else
+    if (AppConstants.platform == "macosx") {
+      return aFile.leafName || aFile.path;
+    }
     return aFile.path;
-#endif
   },
 
   // initAppAndSaveToDiskValues:
   initAppAndSaveToDiskValues: function() {
     var modeGroup = this.dialogElement("mode");
 
     // We don't let users open .exe files or random binary data directly
     // from the browser at the moment because of security concerns.
@@ -913,30 +906,30 @@ nsUnknownContentTypeDialog.prototype = {
     try {
       var needUpdate = this.updateMIMEInfo();
 
       if (this.dialogElement("save").selected) {
         // If we're using a default download location, create a path
         // for the file to be saved to to pass to |saveToDisk| - otherwise
         // we must ask the user to pick a save name.
 
-#if 0
+        /*
         var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
         var targetFile = null;
         try {
           targetFile = prefs.getComplexValue("browser.download.defaultFolder",
                                              Components.interfaces.nsILocalFile);
           var leafName = this.dialogElement("location").getAttribute("realname");
           // Ensure that we don't overwrite any existing files here.
           targetFile = this.validateLeafName(targetFile, leafName, null);
         }
         catch(e) { }
 
         this.mLauncher.saveToDisk(targetFile, false);
-#endif
+        */
 
         // see @notify
         // we cannot use opener's setTimeout, see bug 420405
         this._saveToDiskTimer = Components.classes["@mozilla.org/timer;1"]
                                           .createInstance(nsITimer);
         this._saveToDiskTimer.initWithCallback(this, 0,
                                                nsITimer.TYPE_ONE_SHOT);
       }
@@ -980,142 +973,140 @@ nsUnknownContentTypeDialog.prototype = {
   // dialogElement:  Convenience.
   dialogElement: function(id) {
     return this.mDialog.document.getElementById(id);
   },
 
   // Retrieve the pretty description from the file
   getFileDisplayName: function getFileDisplayName(file)
   {
-#ifdef XP_WIN
-    if (file instanceof Components.interfaces.nsILocalFileWin) {
-      try {
-        return file.getVersionInfoField("FileDescription");
-      } catch (e) {}
+    if (AppConstants.platform == "win") {
+      if (file instanceof Components.interfaces.nsILocalFileWin) {
+        try {
+          return file.getVersionInfoField("FileDescription");
+        } catch (e) {}
+      }
+    } else if (AppConstants.platform == "macosx") {
+      if (file instanceof Components.interfaces.nsILocalFileMac) {
+        try {
+          return file.bundleDisplayName;
+        } catch (e) {}
+      }
     }
-#endif
-#ifdef XP_MACOSX
-    if (file instanceof Components.interfaces.nsILocalFileMac) {
-      try {
-        return file.bundleDisplayName;
-      } catch (e) {}
-    }
-#endif
     return file.leafName;
   },
 
   finishChooseApp: function() {
     if (this.chosenApp) {
       // Show the "handler" menulist since we have a (user-specified)
       // application now.
       this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
 
       // Update dialog.
       var otherHandler = this.dialogElement("otherHandler");
       otherHandler.removeAttribute("hidden");
       otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
-#ifdef XP_WIN
-      otherHandler.label = this.getFileDisplayName(this.chosenApp.executable);
-#else
-      otherHandler.label = this.chosenApp.name;
-#endif
+      if (AppConstants.platform == "win")
+        otherHandler.label = this.getFileDisplayName(this.chosenApp.executable);
+      else
+        otherHandler.label = this.chosenApp.name;
       this.dialogElement("openHandler").selectedIndex = 1;
       this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
 
       this.dialogElement("mode").selectedItem = this.dialogElement("open");
     }
     else {
       var openHandler = this.dialogElement("openHandler");
       var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
       if (!lastSelectedID)
         lastSelectedID = "defaultHandler";
       openHandler.selectedItem = this.dialogElement(lastSelectedID);
     }
   },
   // chooseApp:  Open file picker and prompt user for application.
   chooseApp: function() {
-#ifdef XP_WIN
-    // Protect against the lack of an extension
-    var fileExtension = "";
-    try {
-      fileExtension = this.mLauncher.MIMEInfo.primaryExtension;
-    } catch(ex) {
-    }
+    if (AppConstants.platform == "win") {
+      // Protect against the lack of an extension
+      var fileExtension = "";
+      try {
+        fileExtension = this.mLauncher.MIMEInfo.primaryExtension;
+      } catch(ex) {
+      }
 
-    // Try to use the pretty description of the type, if one is available.
-    var typeString = this.mLauncher.MIMEInfo.description;
+      // Try to use the pretty description of the type, if one is available.
+      var typeString = this.mLauncher.MIMEInfo.description;
 
-    if (!typeString) {
-      // If there is none, use the extension to
-      // identify the file, e.g. "ZIP file"
-      if (fileExtension) {
-        typeString =
-          this.dialogElement("strings").
-          getFormattedString("fileType", [fileExtension.toUpperCase()]);
-      } else {
-        // If we can't even do that, just give up and show the MIME type.
-        typeString = this.mLauncher.MIMEInfo.MIMEType;
+      if (!typeString) {
+        // If there is none, use the extension to
+        // identify the file, e.g. "ZIP file"
+        if (fileExtension) {
+          typeString =
+            this.dialogElement("strings").
+            getFormattedString("fileType", [fileExtension.toUpperCase()]);
+        } else {
+          // If we can't even do that, just give up and show the MIME type.
+          typeString = this.mLauncher.MIMEInfo.MIMEType;
+        }
+      }
+
+      var params = {};
+      params.title =
+        this.dialogElement("strings").getString("chooseAppFilePickerTitle");
+      params.description = typeString;
+      params.filename    = this.mLauncher.suggestedFileName;
+      params.mimeInfo    = this.mLauncher.MIMEInfo;
+      params.handlerApp  = null;
+
+      this.mDialog.openDialog("chrome://global/content/appPicker.xul", null,
+                              "chrome,modal,centerscreen,titlebar,dialog=yes",
+                              params);
+
+      if (params.handlerApp &&
+          params.handlerApp.executable &&
+          params.handlerApp.executable.isFile()) {
+        // Remember the file they chose to run.
+        this.chosenApp = params.handlerApp;
       }
     }
-
-    var params = {};
-    params.title =
-      this.dialogElement("strings").getString("chooseAppFilePickerTitle");
-    params.description = typeString;
-    params.filename    = this.mLauncher.suggestedFileName;
-    params.mimeInfo    = this.mLauncher.MIMEInfo;
-    params.handlerApp  = null;
-
-    this.mDialog.openDialog("chrome://global/content/appPicker.xul", null,
-                            "chrome,modal,centerscreen,titlebar,dialog=yes",
-                            params);
-
-    if (params.handlerApp &&
-        params.handlerApp.executable &&
-        params.handlerApp.executable.isFile()) {
-      // Remember the file they chose to run.
-      this.chosenApp = params.handlerApp;
-    }
-#else
+    else {
 #if MOZ_WIDGET_GTK == 3
-    var nsIApplicationChooser = Components.interfaces.nsIApplicationChooser;
-    var appChooser = Components.classes["@mozilla.org/applicationchooser;1"]
-                               .createInstance(nsIApplicationChooser);
-    appChooser.init(this.mDialog, this.dialogElement("strings").getString("chooseAppFilePickerTitle"));
-    var contentTypeDialogObj = this;
-    let appChooserCallback = function appChooserCallback_done(aResult) {
-      if (aResult) {
-         contentTypeDialogObj.chosenApp = aResult.QueryInterface(Components.interfaces.nsILocalHandlerApp);
-      }
-      contentTypeDialogObj.finishChooseApp();
-    };
-    appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
-    // The finishChooseApp is called from appChooserCallback
-    return;
+      var nsIApplicationChooser = Components.interfaces.nsIApplicationChooser;
+      var appChooser = Components.classes["@mozilla.org/applicationchooser;1"]
+                                 .createInstance(nsIApplicationChooser);
+      appChooser.init(this.mDialog, this.dialogElement("strings").getString("chooseAppFilePickerTitle"));
+      var contentTypeDialogObj = this;
+      let appChooserCallback = function appChooserCallback_done(aResult) {
+        if (aResult) {
+           contentTypeDialogObj.chosenApp = aResult.QueryInterface(Components.interfaces.nsILocalHandlerApp);
+        }
+        contentTypeDialogObj.finishChooseApp();
+      };
+      appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
+      // The finishChooseApp is called from appChooserCallback
+      return;
 #else
-    var nsIFilePicker = Components.interfaces.nsIFilePicker;
-    var fp = Components.classes["@mozilla.org/filepicker;1"]
-                       .createInstance(nsIFilePicker);
-    fp.init(this.mDialog,
-            this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
-            nsIFilePicker.modeOpen);
+      var nsIFilePicker = Components.interfaces.nsIFilePicker;
+      var fp = Components.classes["@mozilla.org/filepicker;1"]
+                         .createInstance(nsIFilePicker);
+      fp.init(this.mDialog,
+              this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
+              nsIFilePicker.modeOpen);
 
-    fp.appendFilters(nsIFilePicker.filterApps);
+      fp.appendFilters(nsIFilePicker.filterApps);
 
-    if (fp.show() == nsIFilePicker.returnOK && fp.file) {
-      // Remember the file they chose to run.
-      var localHandlerApp =
-        Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
-                   createInstance(Components.interfaces.nsILocalHandlerApp);
-      localHandlerApp.executable = fp.file;
-      this.chosenApp = localHandlerApp;
+      if (fp.show() == nsIFilePicker.returnOK && fp.file) {
+        // Remember the file they chose to run.
+        var localHandlerApp =
+          Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
+                     createInstance(Components.interfaces.nsILocalHandlerApp);
+        localHandlerApp.executable = fp.file;
+        this.chosenApp = localHandlerApp;
+      }
+#endif // MOZ_WIDGET_GTK3
     }
-#endif // MOZ_WIDGET_GTK3
-
-#endif // XP_WIN
     this.finishChooseApp();
   },
 
   // Turn this on to get debugging messages.
   debug: false,
 
   // Dump text (if debug is on).
   dump: function( text ) {