Bug 477747 - appcache 'noupdate' event fired too early for master entries. r+sr=jst
authorDave Camp <dcamp@mozilla.com>
Sun, 22 Feb 2009 11:09:10 -0800
changeset 25377 06ec9c2f02a6d5b4617bcdbfee7ca0d5e8980c5d
parent 25376 ad173cf77112b6294dda1acb63e817f798eab5e0
child 25378 d7efb58a314457d11c98de0c976f7fbe65bc5458
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs477747
milestone1.9.2a1pre
Bug 477747 - appcache 'noupdate' event fired too early for master entries. r+sr=jst
dom/tests/mochitest/ajax/offline/updatingImplicit.html
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
--- a/dom/tests/mochitest/ajax/offline/updatingImplicit.html
+++ b/dom/tests/mochitest/ajax/offline/updatingImplicit.html
@@ -4,16 +4,30 @@
 
 <script type="text/javascript" src="/MochiKit/packed.js"></script>
 <script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
 
 <script type="text/javascript">
 
 function manifestUpdated()
 {
+  // Assert that we are properly associated with the application
+  // cache.
+  var req = new XMLHttpRequest;
+  req.open("GET", "namespace2/script3.js", false);
+  try {
+    req.send(null);
+    window.opener.OfflineTest.ok(false, "Able to fetch unlisted resource, not properly associated.");
+  } catch(ex) {
+    window.opener.OfflineTest.ok(true, "Unable to fetch unlisted resource, properly associated.");
+  }
+
+  window.opener.OfflineTest.checkCache("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html",
+                                       true);
+
   window.opener.implicitLoaded(window, false);
 }
 
 function manifestError()
 {
   window.opener.implicitLoaded(window, true);
 }
 
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -1082,16 +1082,17 @@ NS_IMPL_ISUPPORTS1(nsOfflineCacheUpdate,
                    nsIOfflineCacheUpdate)
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate <public>
 //-----------------------------------------------------------------------------
 
 nsOfflineCacheUpdate::nsOfflineCacheUpdate()
     : mState(STATE_UNINITIALIZED)
+    , mOwner(nsnull)
     , mAddedItems(PR_FALSE)
     , mPartialUpdate(PR_FALSE)
     , mSucceeded(PR_TRUE)
     , mObsolete(PR_FALSE)
     , mCurrentItem(-1)
     , mRescheduleCount(0)
 {
 }
@@ -1329,19 +1330,29 @@ nsOfflineCacheUpdate::LoadCompleted()
             mSucceeded = PR_FALSE;
             NotifyError();
             Finish();
             return;
         }
 
         if (!doUpdate) {
             mSucceeded = PR_FALSE;
-            NotifyNoUpdate();
-            Finish();
+
+            for (PRInt32 i = 0; i < mDocuments.Count(); i++) {
+                AssociateDocument(mDocuments[i]);
+            }
+
             ScheduleImplicit();
+
+            // If we didn't need an implicit update, we can
+            // send noupdate and end the update now.
+            if (!mImplicitUpdate) {
+                NotifyNoUpdate();
+                Finish();
+            }
             return;
         }
 
         rv = mApplicationCache->MarkEntry(mManifestItem->mCacheKey,
                                           mManifestItem->mItemType);
         if (NS_FAILED(rv)) {
             mSucceeded = PR_FALSE;
             NotifyError();
@@ -1733,16 +1744,34 @@ nsOfflineCacheUpdate::AddDocument(nsIDOM
     PRBool loadedFromAppCache;
     appCacheChannel->GetLoadedFromApplicationCache(&loadedFromAppCache);
     if (loadedFromAppCache)
         return;
 
     mDocuments.AppendObject(aDocument);
 }
 
+void
+nsOfflineCacheUpdate::SetOwner(nsOfflineCacheUpdateOwner *aOwner)
+{
+    NS_ASSERTION(!mOwner, "Tried to set cache update owner twice.");
+    mOwner = aOwner;
+}
+
+nsresult
+nsOfflineCacheUpdate::UpdateFinished(nsOfflineCacheUpdate *aUpdate)
+{
+    mImplicitUpdate = nsnull;
+
+    NotifyNoUpdate();
+    Finish();
+
+    return NS_OK;
+}
+
 nsresult
 nsOfflineCacheUpdate::ScheduleImplicit()
 {
     if (mDocuments.Count() == 0)
         return NS_OK;
 
     nsresult rv;
 
@@ -1792,19 +1821,22 @@ nsOfflineCacheUpdate::ScheduleImplicit()
         NS_ENSURE_SUCCESS(rv, rv);
 
         added = PR_TRUE;
     }
 
     if (!added)
       return NS_OK;
 
-    rv = update->Schedule();
+    update->SetOwner(this);
+    rv = update->Begin();
     NS_ENSURE_SUCCESS(rv, rv);
 
+    mImplicitUpdate = update;
+
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::AssociateDocument(nsIDOMDocument *aDocument)
 {
     // Check that the document that requested this update was
     // previously associated with an application cache.  If not, it
@@ -1828,31 +1860,25 @@ nsOfflineCacheUpdate::AssociateDocument(
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::Finish()
 {
     LOG(("nsOfflineCacheUpdate::Finish [%p]", this));
 
-    // Because call to service->UpdateFinished(this) at the end of this method
+    // Because the call to UpdateFinished(this) at the end of this method
     // may relese the last reference to this object but we still want to work
     // with it after Finish() call ended, make sure to release this instance in
     // the next thread loop round.
     NS_ADDREF_THIS();
     NS_ProxyRelease(NS_GetCurrentThread(), this, PR_TRUE);
 
     mState = STATE_FINISHED;
 
-    nsOfflineCacheUpdateService* service =
-        nsOfflineCacheUpdateService::EnsureService();
-
-    if (!service)
-        return NS_ERROR_FAILURE;
-
     if (!mPartialUpdate) {
         if (mSucceeded) {
             nsIArray *namespaces = mManifestItem->GetNamespaces();
             nsresult rv = mApplicationCache->AddNamespaces(namespaces);
             if (NS_FAILED(rv)) {
                 NotifyError();
                 mSucceeded = PR_FALSE;
             }
@@ -1883,17 +1909,24 @@ nsOfflineCacheUpdate::Finish()
             for (PRUint32 i = 0; i < mItems.Length(); i++) {
                 mItems[i]->Cancel();
             }
 
             mApplicationCache->Discard();
         }
     }
 
-    return service->UpdateFinished(this);
+    nsresult rv = NS_OK;
+
+    if (mOwner) {
+        rv = mOwner->UpdateFinished(this);
+        mOwner = nsnull;
+    }
+
+    return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate::nsIOfflineCacheUpdate
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsOfflineCacheUpdate::GetUpdateDomain(nsACString &aUpdateDomain)
@@ -2204,16 +2237,18 @@ nsOfflineCacheUpdateService::EnsureServi
 }
 
 nsresult
 nsOfflineCacheUpdateService::Schedule(nsOfflineCacheUpdate *aUpdate)
 {
     LOG(("nsOfflineCacheUpdateService::Schedule [%p, update=%p]",
          this, aUpdate));
 
+    aUpdate->SetOwner(this);
+
     nsresult rv;
     nsCOMPtr<nsIObserverService> observerService =
         do_GetService("@mozilla.org/observer-service;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(aUpdate),
                                      "offline-cache-update-added",
                                      nsnull);
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -198,17 +198,24 @@ private:
 
     // manifest hash data
     nsCOMPtr<nsICryptoHash> mManifestHash;
     PRBool mManifestHashInitialized;
     nsCString mManifestHashValue;
     nsCString mOldManifestHashValue;
 };
 
+class nsOfflineCacheUpdateOwner
+{
+public:
+    virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) = 0;
+};
+
 class nsOfflineCacheUpdate : public nsIOfflineCacheUpdate
+                           , public nsOfflineCacheUpdateOwner
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOFFLINECACHEUPDATE
 
     nsOfflineCacheUpdate();
     ~nsOfflineCacheUpdate();
 
@@ -219,16 +226,20 @@ public:
     nsresult Begin();
     nsresult Cancel();
 
     void LoadCompleted();
     void ManifestCheckCompleted(nsresult aStatus,
                                 const nsCString &aManifestHash);
     void AddDocument(nsIDOMDocument *aDocument);
 
+    void SetOwner(nsOfflineCacheUpdateOwner *aOwner);
+
+    virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate);
+
 private:
     nsresult HandleManifest(PRBool *aDoUpdate);
     nsresult AddURI(nsIURI *aURI, PRUint32 aItemType);
 
     nsresult ProcessNextURI();
 
     // Adds items from the previous cache witha type matching aType.
     // If namespaceFilter is non-null, only items matching the
@@ -252,16 +263,18 @@ private:
         STATE_UNINITIALIZED,
         STATE_INITIALIZED,
         STATE_CHECKING,
         STATE_DOWNLOADING,
         STATE_CANCELLED,
         STATE_FINISHED
     } mState;
 
+    nsOfflineCacheUpdateOwner *mOwner;
+
     PRPackedBool mAddedItems;
     PRPackedBool mPartialUpdate;
     PRPackedBool mSucceeded;
     PRPackedBool mObsolete;
 
     nsCString mUpdateDomain;
     nsCOMPtr<nsIURI> mManifestURI;
 
@@ -284,22 +297,25 @@ private:
     nsCOMArray<nsIOfflineCacheUpdateObserver> mObservers;
 
     /* Documents that requested this update */
     nsCOMArray<nsIDOMDocument> mDocuments;
 
     /* Reschedule count.  When an update is rescheduled due to
      * mismatched manifests, the reschedule count will be increased. */
     PRUint32 mRescheduleCount;
+
+    nsRefPtr<nsOfflineCacheUpdate> mImplicitUpdate;
 };
 
 class nsOfflineCacheUpdateService : public nsIOfflineCacheUpdateService
                                   , public nsIWebProgressListener
                                   , public nsIObserver
                                   , public nsSupportsWeakReference
+                                  , public nsOfflineCacheUpdateOwner
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOFFLINECACHEUPDATESERVICE
     NS_DECL_NSIWEBPROGRESSLISTENER
     NS_DECL_NSIOBSERVER
 
     nsOfflineCacheUpdateService();
@@ -308,17 +324,17 @@ public:
     nsresult Init();
 
     nsresult Schedule(nsOfflineCacheUpdate *aUpdate);
     nsresult Schedule(nsIURI *aManifestURI,
                       nsIURI *aDocumentURI,
                       nsIDOMDocument *aDocument,
                       nsIOfflineCacheUpdate **aUpdate);
 
-    nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate);
+    virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate);
 
     /**
      * Returns the singleton nsOfflineCacheUpdateService without an addref, or
      * nsnull if the service couldn't be created.
      */
     static nsOfflineCacheUpdateService *EnsureService();
 
     /** Addrefs and returns the singleton nsOfflineCacheUpdateService. */