LCOV - code coverage report
Current view: top level - dom/offline - nsDOMOfflineResourceList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 404 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 50 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13