Bug 824697 - Installing a Hosted App that Preloads the Appcache, updating the appcache, manual syncing the app - no updates found; r=fabrice
authorFernando Jiménez <ferjmoreno@gmail.com>
Thu, 10 Jan 2013 18:06:59 +0100
changeset 118410 9cda648d19fa
parent 118409 03fd5f43435d
child 118411 64624cab8dc1
push id21045
push userferjmoreno@gmail.com
push dateThu, 10 Jan 2013 17:07:46 +0000
treeherdermozilla-inbound@9cda648d19fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs824697
milestone21.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 824697 - Installing a Hosted App that Preloads the Appcache, updating the appcache, manual syncing the app - no updates found; r=fabrice
dom/apps/src/Webapps.jsm
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -1155,142 +1155,157 @@ this.DOMApplicationRegistry = {
       app.downloadSize = manifest.size;
       aData.event = "downloadavailable";
       aData.app = {
         downloadAvailable: true,
         downloadSize: manifest.size,
         updateManifest: aManifest
       }
       DOMApplicationRegistry._saveApps(function() {
-        DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK", aData);
+        DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
+                                                aData);
         delete aData.app.updateManifest;
       });
     }
 
-    function updateHostedApp(aManifest) {
+    // A hosted app is updated if the app manifest or the appcache needs
+    // updating. Even if the app manifest has not changed, we still check
+    // for changes in the app cache.
+    // 'aNewManifest' would contain the updated app manifest if
+    // it has actually been updated, while 'aOldManifest' contains the
+    // stored app manifest.
+    function updateHostedApp(aOldManifest, aNewManifest) {
       debug("updateHostedApp " + aData.manifestURL);
-      let id = this._appId(app.origin);
 
       // Clean up the deprecated manifest cache if needed.
       if (id in this._manifestCache) {
         delete this._manifestCache[id];
       }
 
-      // Update the web apps' registration.
-      this.notifyAppsRegistryStart();
+      let manifest;
+      if (aNewManifest) {
+        // Update the web apps' registration.
+        this.notifyAppsRegistryStart();
 #ifdef MOZ_SYS_MSG
-      this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
-        this._unregisterActivities(aResult[0].manifest, app);
-        this._registerSystemMessages(aManifest, app);
-        this._registerActivities(aManifest, app, true);
-      }).bind(this));
+        this._unregisterActivities(aOldManifest, app);
+        this._registerSystemMessages(aNewManifest, app);
+        this._registerActivities(aNewManifest, app, true);
 #else
-      // Nothing else to do but notifying we're ready.
-      this.notifyAppsRegistryReady();
+        // Nothing else to do but notifying we're ready.
+        this.notifyAppsRegistryReady();
 #endif
-
-      // Store the new manifest.
-      let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
-      let manFile = dir.clone();
-      manFile.append("manifest.webapp");
-      this._writeFile(manFile, JSON.stringify(aManifest), function() { });
-
-      let manifest = new ManifestHelper(aManifest, app.origin);
+        // Store the new manifest.
+        let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
+        let manFile = dir.clone();
+        manFile.append("manifest.webapp");
+        this._writeFile(manFile, JSON.stringify(aNewManifest), function() { });
+        manifest = new ManifestHelper(aNewManifest, app.origin);
+      } else {
+        manifest = new ManifestHelper(aOldManifest, app.origin);
+      }
 
       app.installState = "installed";
       app.downloading = false;
       app.downloadSize = 0;
       app.readyToApplyDownload = false;
       app.downloadAvailable = !!manifest.appcache_path;
 
-      app.name = aManifest.name;
-      app.csp = aManifest.csp || "";
+      app.name = manifest.name;
+      app.csp = manifest.csp || "";
       app.updateTime = Date.now();
 
       // Update the registry.
       this.webapps[id] = app;
 
       this._saveApps(function() {
         aData.app = app;
-        app.manifest = aManifest;
+        app.manifest = aNewManifest || aOldManifest;
         if (!manifest.appcache_path) {
           aData.event = "downloadapplied";
           DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
                                                   aData);
         } else {
           // Check if the appcache is updatable, and send "downloadavailable" or
           // "downloadapplied".
           let updateObserver = {
             observe: function(aSubject, aTopic, aObsData) {
               aData.event =
                 aTopic == "offline-cache-update-available" ? "downloadavailable"
                                                            : "downloadapplied";
+              aData.app.downloadAvailable = (aTopic == "downloadavailable");
               DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
                                                       aData);
             }
           }
           updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
                                    app.localId, false, updateObserver);
         }
         delete app.manifest;
       });
 
       // Update the permissions for this app.
-      PermissionsInstaller.installPermissions({ manifest: aManifest,
+      PermissionsInstaller.installPermissions({ manifest: aNewManifest || aOldManifest,
                                                 origin: app.origin,
                                                 manifestURL: aData.manifestURL },
                                               true);
     }
 
-    // For non-removable hosted apps, we only check the appcache.
+    // For non-removable hosted apps that lives in the core apps dir we
+    // only check the appcache because we can't modify the manifest even
+    // if it has changed.
     let onlyCheckAppCache = false;
 
 #ifdef MOZ_WIDGET_GONK
       let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
       onlyCheckAppCache = (app.basePath == appDir.path);
 #endif
 
     if (onlyCheckAppCache) {
       // Bail out for packaged apps.
       if (app.origin.startsWith("app://")) {
         aData.error = "NOT_UPDATABLE";
         aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
         return;
       }
 
       // We need the manifest to check if we have an appcache.
-      let id = this._appId(app.origin);
       this._readManifests([{ id: id }], function(aResult) {
         let manifest = aResult[0].manifest;
         if (!manifest.appcache_path) {
           aData.error = "NOT_UPDATABLE";
           aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
           return;
         }
 
+        app.installState = "installed";
+        app.downloading = false;
+        app.downloadSize = 0;
+        app.readyToApplyDownload = false;
+        app.updateTime = Date.now();
+
         debug("Checking only appcache for " + aData.manifestURL);
         // Check if the appcache is updatable, and send "downloadavailable" or
         // "downloadapplied".
         let updateObserver = {
           observe: function(aSubject, aTopic, aObsData) {
-            debug("appcache result: " + aTopic);
             if (aData.event == "offline-cache-update-available") {
               aData.event = "downloadavailable";
+              app.downloadAvailable = true;
+              aData.app = app;
               DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
                                                       aData);
             } else {
               aData.error = "NOT_UPDATABLE";
               aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
             }
           }
         }
         updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
                                  app.localId, false, updateObserver);
       });
-
       return;
     }
 
     // Try to download a new manifest.
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", aData.manifestURL, true);
     xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
@@ -1306,37 +1321,50 @@ this.DOMApplicationRegistry = {
       if (xhr.status == 200) {
         let manifest = xhr.response;
         if (manifest == null) {
           sendError("MANIFEST_PARSE_ERROR");
           return;
         }
         if (!AppsUtils.checkManifest(manifest)) {
           sendError("INVALID_MANIFEST");
+          return;
         } else if (!AppsUtils.checkInstallAllowed(manifest, app.installOrigin)) {
           sendError("INSTALL_FROM_DENIED");
+          return;
         } else {
           app.etag = xhr.getResponseHeader("Etag");
           app.lastCheckedUpdate = Date.now();
           if (app.origin.startsWith("app://")) {
             updatePackagedApp.call(this, manifest);
           } else {
-            updateHostedApp.call(this, manifest);
+            this._readManifests([{ id: id }], (function(aResult) {
+              updateHostedApp.call(this, aResult[0].manifest, manifest);
+            }).bind(this));
           }
         }
-        this._saveApps();
       } else if (xhr.status == 304) {
-        // The manifest has not changed. We just update lastCheckedUpdate.
-        app.lastCheckedUpdate = Date.now();
-        aData.event = "downloadapplied";
-        aData.app = {
-          lastCheckedUpdate: app.lastCheckedUpdate
+        // The manifest has not changed.
+        if (app.origin.startsWith("app://")) {
+          // If the app is a packaged app, we just send a 'downloadapplied'
+          // event.
+          app.lastCheckedUpdate = Date.now();
+          aData.event = "downloadapplied";
+          aData.app = {
+            lastCheckedUpdate: app.lastCheckedUpdate
+          }
+          aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+          this._saveApps();
+        } else {
+          // For hosted apps, even if the manifest has not changed, we check
+          // for offline cache updates.
+          this._readManifests([{ id: id }], (function(aResult) {
+            updateHostedApp.call(this, aResult[0].manifest, null);
+          }).bind(this));
         }
-        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
-        this._saveApps();
       } else {
         sendError("MANIFEST_URL_ERROR");
       }
     }).bind(this), false);
 
     xhr.addEventListener("error", (function() {
       sendError("NETWORK_ERROR");
     }).bind(this), false);