Bug 1452827: Follow-up: Flush the jar cache after fetch()ing a jar: URI at install. r=bustage
authorKris Maglione <maglione.k@gmail.com>
Tue, 10 Apr 2018 15:19:17 -0700
changeset 412774 7709fe9d13c7f16371995ea48dea6d08dbfaeb64
parent 412773 9ad2b8aabfae6a1c47599fc66d781d5a2a3aa38a
child 412775 64ef6909f615db406084de34e15c5ef25ed19b9b
push id33818
push userapavel@mozilla.com
push dateWed, 11 Apr 2018 14:36:40 +0000
treeherdermozilla-central@cfe6399e142c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbustage
bugs1452827
milestone61.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 1452827: Follow-up: Flush the jar cache after fetch()ing a jar: URI at install. r=bustage MozReview-Commit-ID: BcU9vQrcIvk
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -1,9 +1,9 @@
- /* This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 var EXPORTED_SYMBOLS = [
   "DownloadAddonInstall",
   "LocalAddonInstall",
@@ -121,16 +121,27 @@ function getFile(path, base = null) {
   }
 
   // If the path isn't absolute, we must have a base path.
   let file = base.clone();
   file.appendRelativePath(path);
   return file;
 }
 
+/**
+ * Sends local and remote notifications to flush a JAR file cache entry
+ *
+ * @param aJarFile
+ *        The ZIP/XPI/JAR file as a nsIFile
+ */
+function flushJarCache(aJarFile) {
+  Services.obs.notifyObservers(aJarFile, "flush-cache-entry");
+  Services.mm.broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
+}
+
 const PREF_EM_UPDATE_BACKGROUND_URL   = "extensions.update.background.url";
 const PREF_EM_UPDATE_URL              = "extensions.update.url";
 const PREF_XPI_SIGNATURES_DEV_ROOT    = "xpinstall.signatures.dev-root";
 const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 const FILE_WEB_MANIFEST               = "manifest.json";
 
 const KEY_TEMPDIR                     = "TmpD";
 
@@ -251,16 +262,18 @@ class Package {
     let root = Ci.nsIX509CertDB.AddonsPublicRoot;
     if (!AppConstants.MOZ_REQUIRE_SIGNING &&
         Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
       root = Ci.nsIX509CertDB.AddonsStageRoot;
     }
 
     return this.verifySignedStateForRoot(addon, root);
   }
+
+  flushCache() {}
 }
 
 DirPackage = class DirPackage extends Package {
   constructor(file) {
     super(file, Services.io.newFileURI(file));
   }
 
   hasResource(...path) {
@@ -318,21 +331,26 @@ DirPackage = class DirPackage extends Pa
   }
 };
 
 XPIPackage = class XPIPackage extends Package {
   constructor(file) {
     super(file, getJarURI(file));
 
     this.zipReader = new ZipReader(file);
+    this.needFlush = false;
   }
 
   close() {
     this.zipReader.close();
     this.zipReader = null;
+
+    if (this.needFlush) {
+      this.flushCache();
+    }
   }
 
   async hasResource(...path) {
     return this.zipReader.hasEntry(path.join("/"));
   }
 
   async iterFiles(callback) {
     for (let path of XPCOMUtils.IterStringEnumerator(this.zipReader.findEntries("*"))) {
@@ -341,16 +359,17 @@ XPIPackage = class XPIPackage extends Pa
         path,
         isDir: entry.isDirectory,
         size: entry.realSize,
       });
     }
   }
 
   async readBinary(...path) {
+    this.needFlush = true;
     let response = await fetch(this.rootURI.resolve(path.join("/")));
     return response.arrayBuffer();
   }
 
   verifySignedStateForRoot(addon, root) {
     return new Promise(resolve => {
       let callback = {
         openSignedAppFileFinished(aRv, aZipReader, aCert) {
@@ -364,16 +383,21 @@ XPIPackage = class XPIPackage extends Pa
       };
       // This allows the certificate DB to get the raw JS callback object so the
       // test code can pass through objects that XPConnect would reject.
       callback.wrappedJSObject = callback;
 
       gCertDB.openSignedAppFileAsync(root, this.file, callback);
     });
   }
+
+  flushCache() {
+    flushJarCache(this.file);
+    this.needFlush = false;
+  }
 };
 
 /**
  * Sets permissions on a file
  *
  * @param  aFile
  *         The file or directory to operate on.
  * @param  aPermissions
@@ -910,27 +934,16 @@ var loadManifestFromFile = async functio
   try {
     let addon = await loadManifest(pkg, aInstallLocation);
     return addon;
   } finally {
     pkg.close();
   }
 };
 
-/**
- * Sends local and remote notifications to flush a JAR file cache entry
- *
- * @param aJarFile
- *        The ZIP/XPI/JAR file as a nsIFile
- */
-function flushJarCache(aJarFile) {
-  Services.obs.notifyObservers(aJarFile, "flush-cache-entry");
-  Services.mm.broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
-}
-
 function flushChromeCaches() {
   // Init this, so it will get the notification.
   Services.obs.notifyObservers(null, "startupcache-invalidate");
   // Flush message manager cached scripts
   Services.obs.notifyObservers(null, "message-manager-flush-caches");
   // Also dispatch this event to child processes
   Services.mm.broadcastAsyncMessage(MSG_MESSAGE_MANAGER_CACHES_FLUSH, null);
 }
@@ -939,20 +952,19 @@ function flushChromeCaches() {
  * Creates and returns a new unique temporary file. The caller should delete
  * the file when it is no longer needed.
  *
  * @return an nsIFile that points to a randomly named, initially empty file in
  *         the OS temporary files directory
  */
 function getTemporaryFile() {
   let file = FileUtils.getDir(KEY_TEMPDIR, []);
-  let random = Math.random().toString(36).replace(/0./, "").substr(-3);
+  let random = Math.round(Math.random() * 36 ** 3).toString(36);
   file.append("tmp-" + random + ".xpi");
   file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
-
   return file;
 }
 
 /**
  * Returns the signedState for a given return code and certificate by verifying
  * it against the expected ID.
  */
 function getSignedStatus(aRv, aCert, aAddonID) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
@@ -10,17 +10,19 @@ var gCacheFlushCount = 0;
 var CacheFlushObserver = {
   observe(aSubject, aTopic, aData) {
     if (aTopic != "flush-cache-entry")
       return;
     // Ignore flushes triggered by the fake cert DB
     if (aData == "cert-override")
       return;
 
-    ok(gExpectedFile != null);
+    if (!gExpectedFile) {
+      return;
+    }
     ok(aSubject instanceof Ci.nsIFile);
     equal(aSubject.path, gExpectedFile.path);
     gCacheFlushCount++;
   }
 };
 
 const ADDONS = [
   {