dom/src/offline/nsDOMOfflineResourceList.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsDOMOfflineResourceList.h"
     7 #include "nsIDOMEvent.h"
     8 #include "nsIScriptSecurityManager.h"
     9 #include "nsError.h"
    10 #include "mozilla/dom/DOMStringList.h"
    11 #include "nsIPrefetchService.h"
    12 #include "nsCPrefetchService.h"
    13 #include "nsNetUtil.h"
    14 #include "nsNetCID.h"
    15 #include "nsICacheSession.h"
    16 #include "nsICacheService.h"
    17 #include "nsIOfflineCacheUpdate.h"
    18 #include "nsAutoPtr.h"
    19 #include "nsContentUtils.h"
    20 #include "nsIObserverService.h"
    21 #include "nsIScriptGlobalObject.h"
    22 #include "nsIWebNavigation.h"
    23 #include "mozilla/dom/OfflineResourceListBinding.h"
    24 #include "mozilla/EventDispatcher.h"
    25 #include "mozilla/Preferences.h"
    27 #include "nsXULAppAPI.h"
    28 #define IS_CHILD_PROCESS() \
    29     (GeckoProcessType_Default != XRE_GetProcessType())
    31 using namespace mozilla;
    32 using namespace mozilla::dom;
    34 // Event names
    36 #define CHECKING_STR    "checking"
    37 #define ERROR_STR       "error"
    38 #define NOUPDATE_STR    "noupdate"
    39 #define DOWNLOADING_STR "downloading"
    40 #define PROGRESS_STR    "progress"
    41 #define CACHED_STR      "cached"
    42 #define UPDATEREADY_STR "updateready"
    43 #define OBSOLETE_STR    "obsolete"
    45 // To prevent abuse of the resource list for data storage, the number
    46 // of offline urls and their length are limited.
    48 static const char kMaxEntriesPref[] =  "offline.max_site_resources";
    49 #define DEFAULT_MAX_ENTRIES 100
    50 #define MAX_URI_LENGTH 2048
    52 //
    53 // nsDOMOfflineResourceList
    54 //
    56 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMOfflineResourceList,
    57                                    DOMEventTargetHelper,
    58                                    mCacheUpdate,
    59                                    mPendingEvents)
    61 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMOfflineResourceList)
    62   NS_INTERFACE_MAP_ENTRY(nsIDOMOfflineResourceList)
    63   NS_INTERFACE_MAP_ENTRY(nsIOfflineCacheUpdateObserver)
    64   NS_INTERFACE_MAP_ENTRY(nsIObserver)
    65   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    66 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
    68 NS_IMPL_ADDREF_INHERITED(nsDOMOfflineResourceList, DOMEventTargetHelper)
    69 NS_IMPL_RELEASE_INHERITED(nsDOMOfflineResourceList, DOMEventTargetHelper)
    71 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, checking)
    72 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, error)
    73 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, noupdate)
    74 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, downloading)
    75 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, progress)
    76 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, cached)
    77 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, updateready)
    78 NS_IMPL_EVENT_HANDLER(nsDOMOfflineResourceList, obsolete)
    80 nsDOMOfflineResourceList::nsDOMOfflineResourceList(nsIURI *aManifestURI,
    81                                                    nsIURI *aDocumentURI,
    82                                                    nsPIDOMWindow *aWindow)
    83   : DOMEventTargetHelper(aWindow)
    84   , mInitialized(false)
    85   , mManifestURI(aManifestURI)
    86   , mDocumentURI(aDocumentURI)
    87   , mExposeCacheUpdateStatus(true)
    88   , mStatus(nsIDOMOfflineResourceList::IDLE)
    89   , mCachedKeys(nullptr)
    90   , mCachedKeysCount(0)
    91 {
    92 }
    94 nsDOMOfflineResourceList::~nsDOMOfflineResourceList()
    95 {
    96   ClearCachedKeys();
    97 }
    99 JSObject*
   100 nsDOMOfflineResourceList::WrapObject(JSContext* aCx)
   101 {
   102   return OfflineResourceListBinding::Wrap(aCx, this);
   103 }
   105 nsresult
   106 nsDOMOfflineResourceList::Init()
   107 {
   108   if (mInitialized) {
   109     return NS_OK;
   110   }
   112   if (!mManifestURI) {
   113     return NS_ERROR_DOM_INVALID_STATE_ERR;
   114   }
   116   mManifestURI->GetAsciiSpec(mManifestSpec);
   118   nsresult rv = nsContentUtils::GetSecurityManager()->
   119                    CheckSameOriginURI(mManifestURI, mDocumentURI, true);
   120   NS_ENSURE_SUCCESS(rv, rv);
   122   // Dynamically-managed resources are stored as a separate ownership list
   123   // from the manifest.
   124   nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(mDocumentURI);
   125   if (!innerURI)
   126     return NS_ERROR_FAILURE;
   128   if (!IS_CHILD_PROCESS())
   129   {
   130     mApplicationCacheService =
   131       do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
   132     NS_ENSURE_SUCCESS(rv, rv);
   134     // Check for in-progress cache updates
   135     nsCOMPtr<nsIOfflineCacheUpdateService> cacheUpdateService =
   136       do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &rv);
   137     NS_ENSURE_SUCCESS(rv, rv);
   139     uint32_t numUpdates;
   140     rv = cacheUpdateService->GetNumUpdates(&numUpdates);
   141     NS_ENSURE_SUCCESS(rv, rv);
   143     for (uint32_t i = 0; i < numUpdates; i++) {
   144       nsCOMPtr<nsIOfflineCacheUpdate> cacheUpdate;
   145       rv = cacheUpdateService->GetUpdate(i, getter_AddRefs(cacheUpdate));
   146       NS_ENSURE_SUCCESS(rv, rv);
   148       UpdateAdded(cacheUpdate);
   149       NS_ENSURE_SUCCESS(rv, rv);
   150     }
   151   }
   153   // watch for new offline cache updates
   154   nsCOMPtr<nsIObserverService> observerService =
   155     mozilla::services::GetObserverService();
   156   if (!observerService)
   157     return NS_ERROR_FAILURE;
   159   rv = observerService->AddObserver(this, "offline-cache-update-added", true);
   160   NS_ENSURE_SUCCESS(rv, rv);
   161   rv = observerService->AddObserver(this, "offline-cache-update-completed", true);
   162   NS_ENSURE_SUCCESS(rv, rv);
   164   mInitialized = true;
   166   return NS_OK;
   167 }
   169 void
   170 nsDOMOfflineResourceList::Disconnect()
   171 {
   172   mPendingEvents.Clear();
   174   if (mListenerManager) {
   175     mListenerManager->Disconnect();
   176     mListenerManager = nullptr;
   177   }
   178 }
   180 //
   181 // nsDOMOfflineResourceList::nsIDOMOfflineResourceList
   182 //
   184 already_AddRefed<DOMStringList>
   185 nsDOMOfflineResourceList::GetMozItems(ErrorResult& aRv)
   186 {
   187   if (IS_CHILD_PROCESS()) {
   188     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   189     return nullptr;
   190   }
   192   nsRefPtr<DOMStringList> items = new DOMStringList();
   194   // If we are not associated with an application cache, return an
   195   // empty list.
   196   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
   197   if (!appCache) {
   198     return items.forget();
   199   }
   201   aRv = Init();
   202   if (aRv.Failed()) {
   203     return nullptr;
   204   }
   206   uint32_t length;
   207   char **keys;
   208   aRv = appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC,
   209                                 &length, &keys);
   210   if (aRv.Failed()) {
   211     return nullptr;
   212   }
   214   for (uint32_t i = 0; i < length; i++) {
   215     items->Add(NS_ConvertUTF8toUTF16(keys[i]));
   216   }
   218   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, keys);
   220   return items.forget();
   221 }
   223 NS_IMETHODIMP
   224 nsDOMOfflineResourceList::GetMozItems(nsISupports** aItems)
   225 {
   226   ErrorResult rv;
   227   nsRefPtr<DOMStringList> items = GetMozItems(rv);
   228   items.forget(aItems);
   229   return rv.ErrorCode();
   230 }
   232 NS_IMETHODIMP
   233 nsDOMOfflineResourceList::MozHasItem(const nsAString& aURI, bool* aExists)
   234 {
   235   if (IS_CHILD_PROCESS()) 
   236     return NS_ERROR_NOT_IMPLEMENTED;
   238   nsresult rv = Init();
   239   NS_ENSURE_SUCCESS(rv, rv);
   241   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
   242   if (!appCache) {
   243     return NS_ERROR_DOM_INVALID_STATE_ERR;
   244   }
   246   nsAutoCString key;
   247   rv = GetCacheKey(aURI, key);
   248   NS_ENSURE_SUCCESS(rv, rv);
   250   uint32_t types;
   251   rv = appCache->GetTypes(key, &types);
   252   if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
   253     *aExists = false;
   254     return NS_OK;
   255   }
   256   NS_ENSURE_SUCCESS(rv, rv);
   258   *aExists = ((types & nsIApplicationCache::ITEM_DYNAMIC) != 0);
   259   return NS_OK;
   260 }
   262 NS_IMETHODIMP
   263 nsDOMOfflineResourceList::GetMozLength(uint32_t *aLength)
   264 {
   265   if (IS_CHILD_PROCESS()) 
   266     return NS_ERROR_NOT_IMPLEMENTED;
   268   if (!mManifestURI) {
   269     *aLength = 0;
   270     return NS_OK;
   271   }
   273   nsresult rv = Init();
   274   NS_ENSURE_SUCCESS(rv, rv);
   276   rv = CacheKeys();
   277   NS_ENSURE_SUCCESS(rv, rv);
   279   *aLength = mCachedKeysCount;
   280   return NS_OK;
   281 }
   283 NS_IMETHODIMP
   284 nsDOMOfflineResourceList::MozItem(uint32_t aIndex, nsAString& aURI)
   285 {
   286   if (IS_CHILD_PROCESS()) 
   287     return NS_ERROR_NOT_IMPLEMENTED;
   289   nsresult rv = Init();
   290   NS_ENSURE_SUCCESS(rv, rv);
   292   SetDOMStringToNull(aURI);
   294   rv = CacheKeys();
   295   NS_ENSURE_SUCCESS(rv, rv);
   297   if (aIndex >= mCachedKeysCount)
   298     return NS_ERROR_NOT_AVAILABLE;
   300   CopyUTF8toUTF16(mCachedKeys[aIndex], aURI);
   302   return NS_OK;
   303 }
   305 NS_IMETHODIMP
   306 nsDOMOfflineResourceList::MozAdd(const nsAString& aURI)
   307 {
   308   if (IS_CHILD_PROCESS()) 
   309     return NS_ERROR_NOT_IMPLEMENTED;
   311   nsresult rv = Init();
   312   NS_ENSURE_SUCCESS(rv, rv);
   314   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
   315     return NS_ERROR_DOM_SECURITY_ERR;
   316   }
   318   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
   319   if (!appCache) {
   320     return NS_ERROR_DOM_INVALID_STATE_ERR;
   321   }
   323   if (aURI.Length() > MAX_URI_LENGTH) return NS_ERROR_DOM_BAD_URI;
   325   // this will fail if the URI is not absolute
   326   nsCOMPtr<nsIURI> requestedURI;
   327   rv = NS_NewURI(getter_AddRefs(requestedURI), aURI);
   328   NS_ENSURE_SUCCESS(rv, rv);
   330   nsAutoCString scheme;
   331   rv = requestedURI->GetScheme(scheme);
   332   NS_ENSURE_SUCCESS(rv, rv);
   334   bool match;
   335   rv = mManifestURI->SchemeIs(scheme.get(), &match);
   336   NS_ENSURE_SUCCESS(rv, rv);
   338   if (!match) {
   339     return NS_ERROR_DOM_SECURITY_ERR;
   340   }
   342   uint32_t length;
   343   rv = GetMozLength(&length);
   344   NS_ENSURE_SUCCESS(rv, rv);
   345   uint32_t maxEntries =
   346     Preferences::GetUint(kMaxEntriesPref, DEFAULT_MAX_ENTRIES);
   348   if (length > maxEntries) return NS_ERROR_NOT_AVAILABLE;
   350   ClearCachedKeys();
   352   nsCOMPtr<nsIOfflineCacheUpdate> update =
   353     do_CreateInstance(NS_OFFLINECACHEUPDATE_CONTRACTID, &rv);
   354   NS_ENSURE_SUCCESS(rv, rv);
   356   nsAutoCString clientID;
   357   rv = appCache->GetClientID(clientID);
   358   NS_ENSURE_SUCCESS(rv, rv);
   360   rv = update->InitPartial(mManifestURI, clientID, mDocumentURI);
   361   NS_ENSURE_SUCCESS(rv, rv);
   363   rv = update->AddDynamicURI(requestedURI);
   364   NS_ENSURE_SUCCESS(rv, rv);
   366   rv = update->Schedule();
   367   NS_ENSURE_SUCCESS(rv, rv);
   369   return NS_OK;
   370 }
   372 NS_IMETHODIMP
   373 nsDOMOfflineResourceList::MozRemove(const nsAString& aURI)
   374 {
   375   if (IS_CHILD_PROCESS()) 
   376     return NS_ERROR_NOT_IMPLEMENTED;
   378   nsresult rv = Init();
   379   NS_ENSURE_SUCCESS(rv, rv);
   381   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
   382     return NS_ERROR_DOM_SECURITY_ERR;
   383   }
   385   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
   386   if (!appCache) {
   387     return NS_ERROR_DOM_INVALID_STATE_ERR;
   388   }
   390   nsAutoCString key;
   391   rv = GetCacheKey(aURI, key);
   392   NS_ENSURE_SUCCESS(rv, rv);
   394   ClearCachedKeys();
   396   // XXX: This is a race condition.  remove() is specced to remove
   397   // from the currently associated application cache, but if this
   398   // happens during an update (or after an update, if we haven't
   399   // swapped yet), that remove() will be lost when the next update is
   400   // finished.  Need to bring this issue up.
   402   rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC);
   403   NS_ENSURE_SUCCESS(rv, rv);
   405   return NS_OK;
   406 }
   408 NS_IMETHODIMP
   409 nsDOMOfflineResourceList::GetStatus(uint16_t *aStatus)
   410 {
   411   nsresult rv = Init();
   413   // Init may fail with INVALID_STATE_ERR if there is no manifest URI.
   414   // The status attribute should not throw that exception, convert it
   415   // to an UNCACHED.
   416   if (rv == NS_ERROR_DOM_INVALID_STATE_ERR ||
   417       !nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
   418     *aStatus = nsIDOMOfflineResourceList::UNCACHED;
   419     return NS_OK;
   420   }
   422   NS_ENSURE_SUCCESS(rv, rv);
   424   // If this object is not associated with a cache, return UNCACHED
   425   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
   426   if (!appCache) {
   427     *aStatus = nsIDOMOfflineResourceList::UNCACHED;
   428     return NS_OK;
   429   }
   432   // If there is an update in process, use its status.
   433   if (mCacheUpdate && mExposeCacheUpdateStatus) {
   434     rv = mCacheUpdate->GetStatus(aStatus);
   435     if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) {
   436       return NS_OK;
   437     }
   438   }
   440   if (mAvailableApplicationCache) {
   441     *aStatus = nsIDOMOfflineResourceList::UPDATEREADY;
   442     return NS_OK;
   443   }
   445   *aStatus = mStatus;
   446   return NS_OK;
   447 }
   449 NS_IMETHODIMP
   450 nsDOMOfflineResourceList::Update()
   451 {
   452   nsresult rv = Init();
   453   NS_ENSURE_SUCCESS(rv, rv);
   455   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
   456     return NS_ERROR_DOM_SECURITY_ERR;
   457   }
   459   nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
   460     do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &rv);
   461   NS_ENSURE_SUCCESS(rv, rv);
   463   nsCOMPtr<nsIDOMWindow> window = 
   464     do_QueryInterface(GetOwner());
   466   nsCOMPtr<nsIOfflineCacheUpdate> update;
   467   rv = updateService->ScheduleUpdate(mManifestURI, mDocumentURI,
   468                                      window, getter_AddRefs(update));
   469   NS_ENSURE_SUCCESS(rv, rv);
   471   return NS_OK;
   472 }
   474 NS_IMETHODIMP
   475 nsDOMOfflineResourceList::SwapCache()
   476 {
   477   nsresult rv = Init();
   478   NS_ENSURE_SUCCESS(rv, rv);
   480   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
   481     return NS_ERROR_DOM_SECURITY_ERR;
   482   }
   484   nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache();
   485   if (!currentAppCache) {
   486     return NS_ERROR_DOM_INVALID_STATE_ERR;
   487   }
   489   // Check the current and potentially newly available cache are not identical.
   490   if (mAvailableApplicationCache == currentAppCache) {
   491     return NS_ERROR_DOM_INVALID_STATE_ERR;
   492   }
   494   if (mAvailableApplicationCache) {
   495     nsCString currClientId, availClientId;
   496     currentAppCache->GetClientID(currClientId);
   497     mAvailableApplicationCache->GetClientID(availClientId);
   498     if (availClientId == currClientId)
   499       return NS_ERROR_DOM_INVALID_STATE_ERR;
   500   } else if (mStatus != OBSOLETE) {
   501     return NS_ERROR_DOM_INVALID_STATE_ERR;
   502   }
   504   ClearCachedKeys();
   506   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
   507     GetDocumentAppCacheContainer();
   509   // In the case of an obsolete cache group, newAppCache might be null.
   510   // We will disassociate from the cache in that case.
   511   if (appCacheContainer) {
   512     rv = appCacheContainer->SetApplicationCache(mAvailableApplicationCache);
   513     NS_ENSURE_SUCCESS(rv, rv);
   514   }
   516   mAvailableApplicationCache = nullptr;
   517   mStatus = nsIDOMOfflineResourceList::IDLE;
   519   return NS_OK;
   520 }
   522 //
   523 // nsDOMOfflineResourceList::nsIDOMEventTarget
   524 //
   526 void
   527 nsDOMOfflineResourceList::FirePendingEvents()
   528 {
   529   for (int32_t i = 0; i < mPendingEvents.Count(); ++i) {
   530     bool dummy;
   531     nsCOMPtr<nsIDOMEvent> event = mPendingEvents[i];
   532     DispatchEvent(event, &dummy);
   533   }
   534   mPendingEvents.Clear();
   535 }
   537 nsresult
   538 nsDOMOfflineResourceList::SendEvent(const nsAString &aEventName)
   539 {
   540   // Don't send events to closed windows
   541   if (!GetOwner()) {
   542     return NS_OK;
   543   }
   545   if (!GetOwner()->GetDocShell()) {
   546     return NS_OK;
   547   }
   549   nsCOMPtr<nsIDOMEvent> event;
   550   nsresult rv = EventDispatcher::CreateEvent(this, nullptr, nullptr,
   551                                              NS_LITERAL_STRING("Events"),
   552                                              getter_AddRefs(event));
   553   NS_ENSURE_SUCCESS(rv, rv);
   554   event->InitEvent(aEventName, false, true);
   556   // We assume anyone that managed to call SendEvent is trusted
   557   event->SetTrusted(true);
   559   // If the window is frozen or we're still catching up on events that were
   560   // queued while frozen, save the event for later.
   561   if (GetOwner()->IsFrozen() || mPendingEvents.Count() > 0) {
   562     mPendingEvents.AppendObject(event);
   563     return NS_OK;
   564   }
   566   bool dummy;
   567   DispatchEvent(event, &dummy);
   569   return NS_OK;
   570 }
   573 //
   574 // nsDOMOfflineResourceList::nsIObserver
   575 //
   576 NS_IMETHODIMP
   577 nsDOMOfflineResourceList::Observe(nsISupports *aSubject,
   578                                     const char *aTopic,
   579                                     const char16_t *aData)
   580 {
   581   if (!strcmp(aTopic, "offline-cache-update-added")) {
   582     nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
   583     if (update) {
   584       UpdateAdded(update);
   585     }
   586   } else if (!strcmp(aTopic, "offline-cache-update-completed")) {
   587     nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
   588     if (update) {
   589       UpdateCompleted(update);
   590     }
   591   }
   593   return NS_OK;
   594 }
   596 //
   597 // nsDOMOfflineResourceList::nsIOfflineCacheUpdateObserver
   598 //
   599 NS_IMETHODIMP
   600 nsDOMOfflineResourceList::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate,
   601                                      uint32_t event)
   602 {
   603   mExposeCacheUpdateStatus = 
   604       (event == STATE_CHECKING) ||
   605       (event == STATE_DOWNLOADING) ||
   606       (event == STATE_ITEMSTARTED) ||
   607       (event == STATE_ITEMCOMPLETED) ||
   608       // During notification of "obsolete" we must expose state of the update
   609       (event == STATE_OBSOLETE);
   611   switch (event) {
   612     case STATE_ERROR:
   613       SendEvent(NS_LITERAL_STRING(ERROR_STR));
   614       break;
   615     case STATE_CHECKING:
   616       SendEvent(NS_LITERAL_STRING(CHECKING_STR));
   617       break;
   618     case STATE_NOUPDATE:
   619       SendEvent(NS_LITERAL_STRING(NOUPDATE_STR));
   620       break;
   621     case STATE_OBSOLETE:
   622       mStatus = nsIDOMOfflineResourceList::OBSOLETE;
   623       mAvailableApplicationCache = nullptr;
   624       SendEvent(NS_LITERAL_STRING(OBSOLETE_STR));
   625       break;
   626     case STATE_DOWNLOADING:
   627       SendEvent(NS_LITERAL_STRING(DOWNLOADING_STR));
   628       break;
   629     case STATE_ITEMSTARTED:
   630       SendEvent(NS_LITERAL_STRING(PROGRESS_STR));
   631       break;
   632     case STATE_ITEMCOMPLETED:
   633       // Nothing to do here...
   634       break;
   635   }
   637   return NS_OK;
   638 }
   640 NS_IMETHODIMP
   641 nsDOMOfflineResourceList::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache)
   642 {
   643   nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache();
   644   if (currentAppCache) {
   645     // Document already has a cache, we cannot override it.  swapCache is
   646     // here to do it on demand.
   648     // If the newly available cache is identical to the current cache, then
   649     // just ignore this event.
   650     if (aApplicationCache == currentAppCache) {
   651       return NS_OK;
   652     }
   654     nsCString currClientId, availClientId;
   655     currentAppCache->GetClientID(currClientId);
   656     aApplicationCache->GetClientID(availClientId);
   657     if (availClientId == currClientId) {
   658       return NS_OK;
   659     }
   661     mAvailableApplicationCache = aApplicationCache;
   662     return NS_OK;
   663   }
   665   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
   666     GetDocumentAppCacheContainer();
   668   if (appCacheContainer) {
   669     appCacheContainer->SetApplicationCache(aApplicationCache);
   670   }
   672   mAvailableApplicationCache = nullptr;
   673   return NS_OK;
   674 }
   676 nsresult
   677 nsDOMOfflineResourceList::GetCacheKey(const nsAString &aURI, nsCString &aKey)
   678 {
   679   nsCOMPtr<nsIURI> requestedURI;
   680   nsresult rv = NS_NewURI(getter_AddRefs(requestedURI), aURI);
   681   NS_ENSURE_SUCCESS(rv, rv);
   683   return GetCacheKey(requestedURI, aKey);
   684 }
   686 nsresult
   687 nsDOMOfflineResourceList::UpdateAdded(nsIOfflineCacheUpdate *aUpdate)
   688 {
   689   // Ignore partial updates.
   690   bool partial;
   691   nsresult rv = aUpdate->GetPartial(&partial);
   692   NS_ENSURE_SUCCESS(rv, rv);
   694   if (partial) {
   695     return NS_OK;
   696   }
   698   nsCOMPtr<nsIURI> updateURI;
   699   rv = aUpdate->GetManifestURI(getter_AddRefs(updateURI));
   700   NS_ENSURE_SUCCESS(rv, rv);
   702   bool equals;
   703   rv = updateURI->Equals(mManifestURI, &equals);
   704   NS_ENSURE_SUCCESS(rv, rv);
   706   if (!equals) {
   707     // This update doesn't belong to us
   708     return NS_OK;
   709   }
   711   NS_ENSURE_TRUE(!mCacheUpdate, NS_ERROR_FAILURE);
   713   // We don't need to emit signals here.  Updates are either added
   714   // when they are scheduled (in which case they are always IDLE) or
   715   // they are added when the applicationCache object is initialized, so there
   716   // are no listeners to accept signals anyway.
   718   mCacheUpdate = aUpdate;
   719   mCacheUpdate->AddObserver(this, true);
   721   return NS_OK;
   722 }
   724 already_AddRefed<nsIApplicationCacheContainer>
   725 nsDOMOfflineResourceList::GetDocumentAppCacheContainer()
   726 {
   727   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(GetOwner());
   728   if (!webnav) {
   729     return nullptr;
   730   }
   732   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
   733     do_GetInterface(webnav);
   734   return appCacheContainer.forget();
   735 }
   737 already_AddRefed<nsIApplicationCache>
   738 nsDOMOfflineResourceList::GetDocumentAppCache()
   739 {
   740   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
   741     GetDocumentAppCacheContainer();
   743   if (appCacheContainer) {
   744     nsCOMPtr<nsIApplicationCache> applicationCache;
   745     appCacheContainer->GetApplicationCache(
   746       getter_AddRefs(applicationCache));
   747     return applicationCache.forget();
   748   }
   750   return nullptr;
   751 }
   753 nsresult
   754 nsDOMOfflineResourceList::UpdateCompleted(nsIOfflineCacheUpdate *aUpdate)
   755 {
   756   if (aUpdate != mCacheUpdate) {
   757     // This isn't the update we're watching.
   758     return NS_OK;
   759   }
   761   bool partial;
   762   mCacheUpdate->GetPartial(&partial);
   763   bool isUpgrade;
   764   mCacheUpdate->GetIsUpgrade(&isUpgrade);
   766   bool succeeded;
   767   nsresult rv = mCacheUpdate->GetSucceeded(&succeeded);
   769   mCacheUpdate->RemoveObserver(this);
   770   mCacheUpdate = nullptr;
   772   if (NS_SUCCEEDED(rv) && succeeded && !partial) {
   773     mStatus = nsIDOMOfflineResourceList::IDLE;
   774     if (isUpgrade) {
   775       SendEvent(NS_LITERAL_STRING(UPDATEREADY_STR));
   776     } else {
   777       SendEvent(NS_LITERAL_STRING(CACHED_STR));
   778     }
   779   }
   781   return NS_OK;
   782 }
   784 nsresult
   785 nsDOMOfflineResourceList::GetCacheKey(nsIURI *aURI, nsCString &aKey)
   786 {
   787   nsresult rv = aURI->GetAsciiSpec(aKey);
   788   NS_ENSURE_SUCCESS(rv, rv);
   790   // url fragments aren't used in cache keys
   791   nsAutoCString::const_iterator specStart, specEnd;
   792   aKey.BeginReading(specStart);
   793   aKey.EndReading(specEnd);
   794   if (FindCharInReadable('#', specStart, specEnd)) {
   795     aKey.BeginReading(specEnd);
   796     aKey = Substring(specEnd, specStart);
   797   }
   799   return NS_OK;
   800 }
   802 nsresult
   803 nsDOMOfflineResourceList::CacheKeys()
   804 {
   805   if (IS_CHILD_PROCESS()) 
   806     return NS_ERROR_NOT_IMPLEMENTED;
   808   if (mCachedKeys)
   809     return NS_OK;
   811   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
   812   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
   813   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
   815   uint32_t appId = 0;
   816   bool inBrowser = false;
   817   if (loadContext) {
   818     loadContext->GetAppId(&appId);
   819     loadContext->GetIsInBrowserElement(&inBrowser);
   820   }
   822   nsAutoCString groupID;
   823   mApplicationCacheService->BuildGroupIDForApp(
   824       mManifestURI, appId, inBrowser, groupID);
   826   nsCOMPtr<nsIApplicationCache> appCache;
   827   mApplicationCacheService->GetActiveCache(groupID,
   828                                            getter_AddRefs(appCache));
   830   if (!appCache) {
   831     return NS_ERROR_DOM_INVALID_STATE_ERR;
   832   }
   834   return appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC,
   835                                  &mCachedKeysCount, &mCachedKeys);
   836 }
   838 void
   839 nsDOMOfflineResourceList::ClearCachedKeys()
   840 {
   841   if (mCachedKeys) {
   842     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCachedKeysCount, mCachedKeys);
   843     mCachedKeys = nullptr;
   844     mCachedKeysCount = 0;
   845   }
   846 }

mercurial