Bug 794663 - Allow downloading appcache for a specific appid/browserflag, r=jduell
authorHonza Bambas <honzab.moz@firemni.cz>
Fri, 26 Oct 2012 13:02:47 +0200
changeset 111522 113d5069e67e7bb8c12e5b5f1a36faadcb01c667
parent 111521 17a6bcffcbebe40a14609c3c0b30c063b1ad444d
child 111523 113115cd43f83b23742896cb53b06283f2cfa1df
push idunknown
push userunknown
push dateunknown
reviewersjduell
bugs794663
milestone19.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 794663 - Allow downloading appcache for a specific appid/browserflag, r=jduell
uriloader/prefetch/OfflineCacheUpdateChild.cpp
uriloader/prefetch/OfflineCacheUpdateChild.h
uriloader/prefetch/OfflineCacheUpdateGlue.cpp
uriloader/prefetch/OfflineCacheUpdateGlue.h
uriloader/prefetch/OfflineCacheUpdateParent.cpp
uriloader/prefetch/nsIOfflineCacheUpdate.idl
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
uriloader/prefetch/nsOfflineCacheUpdateService.cpp
--- a/uriloader/prefetch/OfflineCacheUpdateChild.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateChild.cpp
@@ -77,16 +77,18 @@ OfflineCacheUpdateChild::RefcountHitZero
 //-----------------------------------------------------------------------------
 // OfflineCacheUpdateChild <public>
 //-----------------------------------------------------------------------------
 
 OfflineCacheUpdateChild::OfflineCacheUpdateChild(nsIDOMWindow* aWindow)
     : mState(STATE_UNINITIALIZED)
     , mIsUpgrade(false)
     , mIPCActivated(false)
+    , mInBrowser(false)
+    , mAppID(NECKO_NO_APP_ID)
     , mWindow(aWindow)
     , mByteProgress(0)
 {
 }
 
 OfflineCacheUpdateChild::~OfflineCacheUpdateChild()
 {
     LOG(("OfflineCacheUpdateChild::~OfflineCacheUpdateChild [%p]", this));
@@ -178,17 +180,18 @@ OfflineCacheUpdateChild::AssociateDocume
 // OfflineCacheUpdateChild::nsIOfflineCacheUpdate
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 OfflineCacheUpdateChild::Init(nsIURI *aManifestURI,
                               nsIURI *aDocumentURI,
                               nsIDOMDocument *aDocument,
                               nsIFile *aCustomProfileDir,
-                              nsILoadContext *aLoadContext)
+                              uint32_t aAppID,
+                              bool aInBrowser)
 {
     nsresult rv;
 
     // Make sure the service has been initialized
     nsOfflineCacheUpdateService* service =
         nsOfflineCacheUpdateService::EnsureService();
     if (!service)
         return NS_ERROR_FAILURE;
@@ -219,17 +222,18 @@ OfflineCacheUpdateChild::Init(nsIURI *aM
 
     mDocumentURI = aDocumentURI;
 
     mState = STATE_INITIALIZED;
 
     if (aDocument)
         SetDocument(aDocument);
 
-    mLoadContext = aLoadContext;
+    mAppID = aAppID;
+    mInBrowser = aInBrowser;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 OfflineCacheUpdateChild::InitPartial(nsIURI *aManifestURI,
                                   const nsACString& clientID,
                                   nsIURI *aDocumentURI)
@@ -422,29 +426,21 @@ OfflineCacheUpdateChild::Schedule()
     // mDocument is non-null if both:
     // 1. this update was initiated by a document that referred a manifest
     // 2. the document has not already been loaded from the application cache
     // This tells the update to cache this document even in case the manifest
     // has not been changed since the last fetch.
     // See also nsOfflineCacheUpdate::ScheduleImplicit.
     bool stickDocument = mDocument != nullptr; 
 
-    // Carry load context to the parent
-    bool isInBrowserElement = false;
-    uint32_t appId = NECKO_NO_APP_ID;
-    if (mLoadContext) {
-        mLoadContext->GetIsInBrowserElement(&isInBrowserElement);
-        mLoadContext->GetAppId(&appId);
-    }
-
     // Need to addref ourself here, because the IPC stack doesn't hold
     // a reference to us. Will be released in RecvFinish() that identifies 
     // the work has been done.
     child->SendPOfflineCacheUpdateConstructor(this, manifestURI, documentURI,
-                                              isInBrowserElement, appId,
+                                              mInBrowser, mAppID,
                                               stickDocument);
 
     mIPCActivated = true;
     this->AddRef();
 
     return NS_OK;
 }
 
--- a/uriloader/prefetch/OfflineCacheUpdateChild.h
+++ b/uriloader/prefetch/OfflineCacheUpdateChild.h
@@ -68,17 +68,19 @@ private:
     bool mSucceeded;
     bool mIPCActivated;
 
     nsCString mUpdateDomain;
     nsCOMPtr<nsIURI> mManifestURI;
     nsCOMPtr<nsIURI> mDocumentURI;
 
     nsCOMPtr<nsIObserverService> mObserverService;
-    nsCOMPtr<nsILoadContext> mLoadContext;
+
+    uint32_t mAppID;
+    bool mInBrowser;
 
     /* Clients watching this update for changes */
     nsCOMArray<nsIWeakReference> mWeakObservers;
     nsCOMArray<nsIOfflineCacheUpdateObserver> mObservers;
 
     /* Document that requested this update */
     nsCOMPtr<nsIDOMDocument> mDocument;
 
--- a/uriloader/prefetch/OfflineCacheUpdateGlue.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateGlue.cpp
@@ -88,27 +88,28 @@ OfflineCacheUpdateGlue::Schedule()
     return mUpdate->Schedule();
 }
 
 NS_IMETHODIMP
 OfflineCacheUpdateGlue::Init(nsIURI *aManifestURI, 
                              nsIURI *aDocumentURI,
                              nsIDOMDocument *aDocument,
                              nsIFile *aCustomProfileDir,
-                             nsILoadContext *aLoadContext)
+                             uint32_t aAppID,
+                             bool aInBrowser)
 {
     if (!EnsureUpdate())
         return NS_ERROR_NULL_POINTER;
 
     mDocumentURI = aDocumentURI;
 
     if (aDocument)
         SetDocument(aDocument);
 
-    return mUpdate->Init(aManifestURI, aDocumentURI, nullptr, aCustomProfileDir, aLoadContext);
+    return mUpdate->Init(aManifestURI, aDocumentURI, nullptr, aCustomProfileDir, aAppID, aInBrowser);
 }
 
 void
 OfflineCacheUpdateGlue::SetDocument(nsIDOMDocument *aDocument)
 {
     // The design is one document for one cache update on the content process.
     NS_ASSERTION(!mDocument, 
                  "Setting more then a single document on an instance of OfflineCacheUpdateGlue");
--- a/uriloader/prefetch/OfflineCacheUpdateGlue.h
+++ b/uriloader/prefetch/OfflineCacheUpdateGlue.h
@@ -48,17 +48,18 @@ private:
 
 public:
     NS_ADJUSTED_FORWARD_NSIOFFLINECACHEUPDATE(EnsureUpdate())
     NS_IMETHOD Schedule(void);
     NS_IMETHOD Init(nsIURI *aManifestURI, 
                     nsIURI *aDocumentURI,
                     nsIDOMDocument *aDocument,
                     nsIFile *aCustomProfileDir,
-                    nsILoadContext *aLoadContext);
+                    uint32_t aAppID,
+                    bool aInBrowser);
 
     NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER
 
     OfflineCacheUpdateGlue();
     ~OfflineCacheUpdateGlue();
 
     void SetDocument(nsIDOMDocument *aDocument);
 
--- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp
@@ -70,20 +70,16 @@ nsresult
 OfflineCacheUpdateParent::Schedule(const URIParams& aManifestURI,
                                    const URIParams& aDocumentURI,
                                    const bool& isInBrowserElement,
                                    const uint32_t& appId,
                                    const bool& stickDocument)
 {
     LOG(("OfflineCacheUpdateParent::RecvSchedule [%p]", this));
 
-    // Load context members
-    mIsInBrowserElement = isInBrowserElement;
-    mAppId = appId;
-
     nsRefPtr<nsOfflineCacheUpdate> update;
     nsCOMPtr<nsIURI> manifestURI = DeserializeURI(aManifestURI);
     if (!manifestURI)
         return NS_ERROR_FAILURE;
 
     nsOfflineCacheUpdateService* service =
         nsOfflineCacheUpdateService::EnsureService();
     if (!service)
@@ -99,23 +95,25 @@ OfflineCacheUpdateParent::Schedule(const
 
     nsCOMPtr<nsIURI> documentURI = DeserializeURI(aDocumentURI);
     if (!documentURI)
         return NS_ERROR_FAILURE;
 
     if (!NS_SecurityCompareURIs(manifestURI, documentURI, false))
         return NS_ERROR_DOM_SECURITY_ERR;
 
-    service->FindUpdate(manifestURI, this, getter_AddRefs(update));
+    service->FindUpdate(manifestURI, appId, isInBrowserElement,
+                        getter_AddRefs(update));
     if (!update) {
         update = new nsOfflineCacheUpdate();
 
         // Leave aDocument argument null. Only glues and children keep 
         // document instances.
-        rv = update->Init(manifestURI, documentURI, nullptr, nullptr, this);
+        rv = update->Init(manifestURI, documentURI, nullptr, nullptr,
+                          appId, isInBrowserElement);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = update->Schedule();
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     update->AddObserver(this, false);
 
--- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl
+++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl
@@ -10,17 +10,16 @@ interface nsIDOMWindow;
 interface nsIDOMNode;
 interface nsIDOMDocument;
 interface nsIDOMLoadStatus;
 interface nsIOfflineCacheUpdate;
 interface nsIPrincipal;
 interface nsIPrefBranch;
 interface nsIApplicationCache;
 interface nsIFile;
-interface nsILoadContext;
 interface nsIObserver;
 
 [scriptable, uuid(47360d57-8ef4-4a5d-8865-1a27a739ad1a)]
 interface nsIOfflineCacheUpdateObserver : nsISupports {
   const unsigned long STATE_ERROR = 1;
   const unsigned long STATE_CHECKING = 2;
   const unsigned long STATE_NOUPDATE = 3;
   const unsigned long STATE_OBSOLETE = 4;
@@ -59,17 +58,17 @@ interface nsIOfflineCacheUpdateObserver 
  * Each update object maintains a list of nsIDOMLoadStatus items for the
  * resources it is updating.  The list of these items will be available
  * after the object is scheduled.
  *
  * One update object will be updating at a time.  The active object will
  * load its items one by one, sending itemCompleted() to any registered
  * observers.
  */
-[scriptable, uuid(91d356fa-4eaf-4de2-9870-bb92854cccfe)]
+[scriptable, uuid(91b94446-5d91-4089-bed7-edfab25824a7)]
 interface nsIOfflineCacheUpdate : nsISupports {
   /**
    * Fetch the status of the running update.  This will return a value
    * defined in nsIDOMOfflineResourceList.
    */
   readonly attribute unsigned short status;
 
   /**
@@ -105,17 +104,18 @@ interface nsIOfflineCacheUpdate : nsISup
    *
    * @param aManifestURI
    *        The manifest URI to be checked.
    * @param aDocumentURI
    *        The page that is requesting the update.
    */
   void init(in nsIURI aManifestURI, in nsIURI aDocumentURI, in nsIDOMDocument aDocument,
             [optional] in nsIFile aCustomProfileDir,
-            [optional] in nsILoadContext aLoadContext);
+            [optional] in unsigned long aAppId,
+            [optional] in boolean aInBrowser);
 
   /**
    * Initialize the update for partial processing. 
    *
    * @param aManifestURI
    *        The manifest URI of the related cache.
    * @param aClientID
    *        Client  ID of the cache to store resource to. This ClientID
@@ -185,17 +185,17 @@ interface nsIOfflineCacheUpdate : nsISup
   void removeObserver(in nsIOfflineCacheUpdateObserver aObserver);
 
   /**
    * Return the number of bytes downloaded so far
    */
   readonly attribute uint64_t byteProgress;
 };
 
-[scriptable, uuid(9ff7f81f-114a-4876-ad1b-f3910418e4a6)]
+[scriptable, uuid(cf362a31-4166-4994-8443-b68704ecdcc0)]
 interface nsIOfflineCacheUpdateService : nsISupports {
     /**
      * Constants for the offline-app permission.
      *
      * XXX: This isn't a great place for this, but it's really the only
      * private offline-app-related interface
      */
 
@@ -225,16 +225,27 @@ interface nsIOfflineCacheUpdateService :
      * be stored to a custom profile directory.  There is no coalescing of
      * manifests by manifest URL.
      */
     nsIOfflineCacheUpdate scheduleCustomProfileUpdate(in nsIURI aManifestURI,
                                                       in nsIURI aDocumentURI,
                                                       in nsIFile aProfileDir);
 
     /**
+     * Schedule a cache update for a given offline manifest using app cache
+     * bound to the given appID+inBrowser flag.  If an existing update is
+     * scheduled or running, that update will be returned. Otherwise a new
+     * update will be scheduled.
+     */
+    nsIOfflineCacheUpdate scheduleAppUpdate(in nsIURI aManifestURI,
+                                            in nsIURI aDocumentURI,
+                                            in unsigned long aAppID,
+                                            in boolean aInBrowser);
+
+    /**
      * Schedule a cache update for a manifest when the document finishes
      * loading.
      */
     void scheduleOnDocumentStop(in nsIURI aManifestURI,
                                 in nsIURI aDocumentURI,
                                 in nsIDOMDocument aDocument);
 
     /**
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -1166,16 +1166,18 @@ NS_IMPL_ISUPPORTS3(nsOfflineCacheUpdate,
 nsOfflineCacheUpdate::nsOfflineCacheUpdate()
     : mState(STATE_UNINITIALIZED)
     , mOwner(nullptr)
     , mAddedItems(false)
     , mPartialUpdate(false)
     , mOnlyCheckUpdate(false)
     , mSucceeded(true)
     , mObsolete(false)
+    , mAppID(NECKO_NO_APP_ID)
+    , mInBrowser(false)
     , mItemsInProgress(0)
     , mRescheduleCount(0)
     , mPinnedEntryRetriesCount(0)
     , mPinned(false)
 {
 }
 
 nsOfflineCacheUpdate::~nsOfflineCacheUpdate()
@@ -1226,17 +1228,18 @@ nsOfflineCacheUpdate::InitInternal(nsIUR
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::Init(nsIURI *aManifestURI,
                            nsIURI *aDocumentURI,
                            nsIDOMDocument *aDocument,
                            nsIFile *aCustomProfileDir,
-                           nsILoadContext *aLoadContext)
+                           uint32_t aAppID,
+                           bool aInBrowser)
 {
     nsresult rv;
 
     // Make sure the service has been initialized
     nsOfflineCacheUpdateService* service =
         nsOfflineCacheUpdateService::EnsureService();
     if (!service)
         return NS_ERROR_FAILURE;
@@ -1268,36 +1271,37 @@ nsOfflineCacheUpdate::Init(nsIURI *aMani
                                                         aCustomProfileDir,
                                                         kCustomProfileQuota,
                                                         getter_AddRefs(mApplicationCache));
         NS_ENSURE_SUCCESS(rv, rv);
 
         mCustomProfileDir = aCustomProfileDir;
     }
     else {
-        rv = cacheService->BuildGroupID(aManifestURI,
-                                        aLoadContext,
-                                        mGroupID);
+        rv = cacheService->BuildGroupIDForApp(aManifestURI,
+                                              aAppID, aInBrowser,
+                                              mGroupID);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = cacheService->GetActiveCache(mGroupID,
                                           getter_AddRefs(mPreviousApplicationCache));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = cacheService->CreateApplicationCache(mGroupID,
                                                   getter_AddRefs(mApplicationCache));
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aDocumentURI,
                                                              NULL,
                                                              &mPinned);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    mLoadContext = aLoadContext;
+    mAppID = aAppID;
+    mInBrowser = aInBrowser;
 
     mState = STATE_INITIALIZED;
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::InitForUpdateCheck(nsIURI *aManifestURI,
                                          uint32_t aAppID,
@@ -1692,17 +1696,17 @@ nsOfflineCacheUpdate::ManifestCheckCompl
         // correct.
         FinishNoNotify();
 
         nsRefPtr<nsOfflineCacheUpdate> newUpdate =
             new nsOfflineCacheUpdate();
         // Leave aDocument argument null. Only glues and children keep
         // document instances.
         newUpdate->Init(mManifestURI, mDocumentURI, nullptr,
-                        mCustomProfileDir, mLoadContext);
+                        mCustomProfileDir, mAppID, mInBrowser);
 
         // In a rare case the manifest will not be modified on the next refetch
         // transfer all master document URIs to the new update to ensure that
         // all documents refering it will be properly cached.
         for (int32_t i = 0; i < mDocumentURIs.Count(); i++) {
             newUpdate->StickDocument(mDocumentURIs[i]);
         }
 
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -32,16 +32,17 @@
 #include "nsWeakReference.h"
 #include "nsICryptoHash.h"
 #include "mozilla/Attributes.h"
 
 class nsOfflineCacheUpdate;
 
 class nsICacheEntryDescriptor;
 class nsIUTF8StringEnumerator;
+class nsILoadContext;
 
 class nsOfflineCacheUpdateItem : public nsIDOMLoadStatus
                                , public nsIStreamListener
                                , public nsIRunnable
                                , public nsIInterfaceRequestor
                                , public nsIChannelEventSink
 {
 public:
@@ -259,17 +260,20 @@ private:
     bool mSucceeded;
     bool mObsolete;
 
     nsCString mUpdateDomain;
     nsCString mGroupID;
     nsCOMPtr<nsIURI> mManifestURI;
     nsCOMPtr<nsIURI> mDocumentURI;
     nsCOMPtr<nsIFile> mCustomProfileDir;
-    nsCOMPtr<nsILoadContext> mLoadContext;
+
+    uint32_t mAppID;
+    bool mInBrowser;
+
     nsCOMPtr<nsIObserver> mUpdateAvailableObserver;
 
     nsCOMPtr<nsIApplicationCache> mApplicationCache;
     nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache;
 
     nsCOMPtr<nsIObserverService> mObserverService;
 
     nsRefPtr<nsOfflineManifestItem> mManifestItem;
@@ -312,24 +316,27 @@ public:
 
     nsOfflineCacheUpdateService();
     ~nsOfflineCacheUpdateService();
 
     nsresult Init();
 
     nsresult ScheduleUpdate(nsOfflineCacheUpdate *aUpdate);
     nsresult FindUpdate(nsIURI *aManifestURI,
-                        nsILoadContext *aLoadContext,
+                        uint32_t aAppID,
+                        bool aInBrowser,
                         nsOfflineCacheUpdate **aUpdate);
 
     nsresult Schedule(nsIURI *aManifestURI,
                       nsIURI *aDocumentURI,
                       nsIDOMDocument *aDocument,
                       nsIDOMWindow* aWindow,
                       nsIFile* aCustomProfileDir,
+                      uint32_t aAppID,
+                      bool aInBrowser,
                       nsIOfflineCacheUpdate **aUpdate);
 
     virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate);
 
     /**
      * Returns the singleton nsOfflineCacheUpdateService without an addref, or
      * nullptr if the service couldn't be created.
      */
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -76,16 +76,49 @@ public:
     AutoFreeArray(uint32_t count, char **values)
         : mCount(count), mValues(values) {};
     ~AutoFreeArray() { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mValues); }
 private:
     uint32_t mCount;
     char **mValues;
 };
 
+namespace { // anon
+
+nsresult
+GetAppIDAndInBrowserFromWindow(nsIDOMWindow *aWindow,
+                               uint32_t *aAppId,
+                               bool *aInBrowser)
+{
+    *aAppId = NECKO_NO_APP_ID;
+    *aInBrowser = false;
+
+    if (!aWindow) {
+        return NS_OK;
+    }
+
+    nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
+    nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
+    if (!loadContext) {
+        return NS_OK;
+    }
+
+    nsresult rv;
+
+    rv = loadContext->GetAppId(aAppId);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = loadContext->GetIsInBrowserElement(aInBrowser);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+}
+
+} // anon
+
 //-----------------------------------------------------------------------------
 // nsOfflineCachePendingUpdate
 //-----------------------------------------------------------------------------
 
 class nsOfflineCachePendingUpdate MOZ_FINAL : public nsIWebProgressListener
                                             , public nsSupportsWeakReference
 {
 public:
@@ -161,19 +194,26 @@ nsOfflineCachePendingUpdate::OnStateChan
         return NS_OK;
     }
 
     LOG(("nsOfflineCachePendingUpdate::OnStateChange [%p, doc=%p]",
          this, progressDoc.get()));
 
     // Only schedule the update if the document loaded successfully
     if (NS_SUCCEEDED(aStatus)) {
+        // Get extended origin attributes
+        uint32_t appId;
+        bool isInBrowserElement;
+        nsresult rv = GetAppIDAndInBrowserFromWindow(window, &appId, &isInBrowserElement);
+        NS_ENSURE_SUCCESS(rv, rv);
+
         nsCOMPtr<nsIOfflineCacheUpdate> update;
         mService->Schedule(mManifestURI, mDocumentURI,
-                           updateDoc, window, nullptr, getter_AddRefs(update));
+                           updateDoc, window, nullptr,
+                           appId, isInBrowserElement, getter_AddRefs(update));
     }
 
     aWebProgress->RemoveProgressListener(this);
     NS_RELEASE_THIS();
 
     return NS_OK;
 }
 
@@ -400,29 +440,30 @@ nsOfflineCacheUpdateService::GetUpdate(u
         *aUpdate = nullptr;
     }
 
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdateService::FindUpdate(nsIURI *aManifestURI,
-                                        nsILoadContext *aLoadContext,
+                                        uint32_t aAppID,
+                                        bool aInBrowser,
                                         nsOfflineCacheUpdate **aUpdate)
 {
     nsresult rv;
 
     nsCOMPtr<nsIApplicationCacheService> cacheService =
         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoCString groupID;
-    rv = cacheService->BuildGroupID(aManifestURI,
-                                    aLoadContext,
-                                    groupID);
+    rv = cacheService->BuildGroupIDForApp(aManifestURI,
+                                          aAppID, aInBrowser,
+                                          groupID);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsRefPtr<nsOfflineCacheUpdate> update;
     for (uint32_t i = 0; i < mUpdates.Length(); i++) {
         update = mUpdates[i];
 
         bool partial;
         rv = update->GetPartial(&partial);
@@ -443,65 +484,79 @@ nsOfflineCacheUpdateService::FindUpdate(
 }
 
 nsresult
 nsOfflineCacheUpdateService::Schedule(nsIURI *aManifestURI,
                                       nsIURI *aDocumentURI,
                                       nsIDOMDocument *aDocument,
                                       nsIDOMWindow* aWindow,
                                       nsIFile* aCustomProfileDir,
+                                      uint32_t aAppID,
+                                      bool aInBrowser,
                                       nsIOfflineCacheUpdate **aUpdate)
 {
     nsCOMPtr<nsIOfflineCacheUpdate> update;
     if (GeckoProcessType_Default != XRE_GetProcessType()) {
         update = new OfflineCacheUpdateChild(aWindow);
     }
     else {
         update = new OfflineCacheUpdateGlue();
     }
 
     nsresult rv;
 
-    nsCOMPtr<nsILoadContext> loadContext;
-    if (aWindow) {
-        nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
-        loadContext = do_QueryInterface(webNav);
-    }
-
     rv = update->Init(aManifestURI, aDocumentURI, aDocument,
-                      aCustomProfileDir, loadContext);
+                      aCustomProfileDir, aAppID, aInBrowser);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = update->Schedule();
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ADDREF(*aUpdate = update);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOfflineCacheUpdateService::ScheduleUpdate(nsIURI *aManifestURI,
                                             nsIURI *aDocumentURI,
                                             nsIDOMWindow *aWindow,
                                             nsIOfflineCacheUpdate **aUpdate)
 {
-    return Schedule(aManifestURI, aDocumentURI, nullptr, aWindow, nullptr, aUpdate);
+    // Get extended origin attributes
+    uint32_t appId;
+    bool isInBrowser;
+    nsresult rv = GetAppIDAndInBrowserFromWindow(aWindow, &appId, &isInBrowser);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return Schedule(aManifestURI, aDocumentURI, nullptr, aWindow, nullptr,
+                    appId, isInBrowser, aUpdate);
 }
 
 NS_IMETHODIMP
 nsOfflineCacheUpdateService::ScheduleCustomProfileUpdate(nsIURI *aManifestURI,
                                                          nsIURI *aDocumentURI,
                                                          nsIFile *aProfileDir,
                                                          nsIOfflineCacheUpdate **aUpdate)
 {
     // The profile directory is mandatory
     NS_ENSURE_ARG(aProfileDir);
 
-    return Schedule(aManifestURI, aDocumentURI, nullptr, nullptr, aProfileDir, aUpdate);
+    return Schedule(aManifestURI, aDocumentURI, nullptr, nullptr, aProfileDir,
+                    NECKO_NO_APP_ID, false, aUpdate);
+}
+
+NS_IMETHODIMP
+nsOfflineCacheUpdateService::ScheduleAppUpdate(nsIURI *aManifestURI,
+                                               nsIURI *aDocumentURI,
+                                               uint32_t aAppID, bool aInBrowser,
+                                               nsIOfflineCacheUpdate **aUpdate)
+{
+    return Schedule(aManifestURI, aDocumentURI, nullptr, nullptr, nullptr,
+                    aAppID, aInBrowser, aUpdate);
 }
 
 NS_IMETHODIMP nsOfflineCacheUpdateService::CheckForUpdate(nsIURI *aManifestURI,
                                                           uint32_t aAppID,
                                                           bool aInBrowser,
                                                           nsIObserver *aObserver)
 {
     if (GeckoProcessType_Default != XRE_GetProcessType()) {