LCOV - code coverage report
Current view: top level - uriloader/prefetch - nsOfflineCacheUpdateService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 56 266 21.1 %
Date: 2017-07-14 16:53:18 Functions: 9 37 24.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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/. */
       5             : 
       6             : #include "OfflineCacheUpdateChild.h"
       7             : #include "OfflineCacheUpdateParent.h"
       8             : #include "nsXULAppAPI.h"
       9             : #include "OfflineCacheUpdateGlue.h"
      10             : #include "nsOfflineCacheUpdate.h"
      11             : 
      12             : #include "nsCPrefetchService.h"
      13             : #include "nsCURILoader.h"
      14             : #include "nsIApplicationCacheContainer.h"
      15             : #include "nsIApplicationCacheChannel.h"
      16             : #include "nsIApplicationCacheService.h"
      17             : #include "nsICachingChannel.h"
      18             : #include "nsIContent.h"
      19             : #include "nsIDocShell.h"
      20             : #include "nsIDocumentLoader.h"
      21             : #include "nsIDOMElement.h"
      22             : #include "nsIDOMWindow.h"
      23             : #include "nsIDOMOfflineResourceList.h"
      24             : #include "nsIDocument.h"
      25             : #include "nsIObserverService.h"
      26             : #include "nsIURL.h"
      27             : #include "nsIWebProgress.h"
      28             : #include "nsIWebNavigation.h"
      29             : #include "nsICryptoHash.h"
      30             : #include "nsIPermissionManager.h"
      31             : #include "nsIPrincipal.h"
      32             : #include "nsNetCID.h"
      33             : #include "nsServiceManagerUtils.h"
      34             : #include "nsStreamUtils.h"
      35             : #include "nsThreadUtils.h"
      36             : #include "nsProxyRelease.h"
      37             : #include "mozilla/Logging.h"
      38             : #include "nsIAsyncVerifyRedirectCallback.h"
      39             : #include "mozilla/Preferences.h"
      40             : #include "mozilla/Attributes.h"
      41             : #include "mozilla/SizePrintfMacros.h"
      42             : #include "mozilla/Unused.h"
      43             : #include "nsIDiskSpaceWatcher.h"
      44             : #include "nsIDocShell.h"
      45             : #include "nsIDocShellTreeItem.h"
      46             : #include "nsIDocShellTreeOwner.h"
      47             : #include "mozilla/dom/ContentChild.h"
      48             : #include "mozilla/dom/PermissionMessageUtils.h"
      49             : #include "nsContentUtils.h"
      50             : #include "mozilla/Unused.h"
      51             : 
      52             : using namespace mozilla;
      53             : using namespace mozilla::dom;
      54             : 
      55             : static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr;
      56             : static bool sAllowOfflineCache = true;
      57             : 
      58             : nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::mAllowedDomains = nullptr;
      59             : 
      60           1 : nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::AllowedDomains()
      61             : {
      62           1 :     if (!mAllowedDomains)
      63           1 :         mAllowedDomains = new nsTHashtable<nsCStringHashKey>();
      64             : 
      65           1 :     return mAllowedDomains;
      66             : }
      67             : 
      68             : 
      69             : typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent;
      70             : typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild;
      71             : typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue;
      72             : 
      73             : //
      74             : // To enable logging (see mozilla/Logging.h for full details):
      75             : //
      76             : //    set MOZ_LOG=nsOfflineCacheUpdate:5
      77             : //    set MOZ_LOG_FILE=offlineupdate.log
      78             : //
      79             : // this enables LogLevel::Debug level information and places all output in
      80             : // the file offlineupdate.log
      81             : //
      82             : LazyLogModule gOfflineCacheUpdateLog("nsOfflineCacheUpdate");
      83             : 
      84             : #undef LOG
      85             : #define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args)
      86             : 
      87             : #undef LOG_ENABLED
      88             : #define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug)
      89             : 
      90             : //-----------------------------------------------------------------------------
      91             : // nsOfflineCachePendingUpdate
      92             : //-----------------------------------------------------------------------------
      93             : 
      94             : class nsOfflineCachePendingUpdate final : public nsIWebProgressListener
      95             :                                         , public nsSupportsWeakReference
      96             : {
      97             : public:
      98             :     NS_DECL_ISUPPORTS
      99             :     NS_DECL_NSIWEBPROGRESSLISTENER
     100             : 
     101           0 :     nsOfflineCachePendingUpdate(nsOfflineCacheUpdateService *aService,
     102             :                                 nsIURI *aManifestURI,
     103             :                                 nsIURI *aDocumentURI,
     104             :                                 nsIPrincipal* aLoadingPrincipal,
     105             :                                 nsIDOMDocument *aDocument)
     106           0 :         : mService(aService)
     107             :         , mManifestURI(aManifestURI)
     108             :         , mDocumentURI(aDocumentURI)
     109             :         , mLoadingPrincipal(aLoadingPrincipal)
     110           0 :         , mDidReleaseThis(false)
     111             :         {
     112           0 :             mDocument = do_GetWeakReference(aDocument);
     113           0 :         }
     114             : 
     115             : private:
     116           0 :     ~nsOfflineCachePendingUpdate() {}
     117             : 
     118             :     RefPtr<nsOfflineCacheUpdateService> mService;
     119             :     nsCOMPtr<nsIURI> mManifestURI;
     120             :     nsCOMPtr<nsIURI> mDocumentURI;
     121             :     nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
     122             :     nsCOMPtr<nsIWeakReference> mDocument;
     123             :     bool mDidReleaseThis;
     124             : };
     125             : 
     126           0 : NS_IMPL_ISUPPORTS(nsOfflineCachePendingUpdate,
     127             :                   nsIWebProgressListener,
     128             :                   nsISupportsWeakReference)
     129             : 
     130             : //-----------------------------------------------------------------------------
     131             : // nsOfflineCacheUpdateService::nsIWebProgressListener
     132             : //-----------------------------------------------------------------------------
     133             : 
     134             : NS_IMETHODIMP
     135           0 : nsOfflineCachePendingUpdate::OnProgressChange(nsIWebProgress *aProgress,
     136             :                                               nsIRequest *aRequest,
     137             :                                               int32_t curSelfProgress,
     138             :                                               int32_t maxSelfProgress,
     139             :                                               int32_t curTotalProgress,
     140             :                                               int32_t maxTotalProgress)
     141             : {
     142           0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     143           0 :     return NS_OK;
     144             : }
     145             : 
     146             : NS_IMETHODIMP
     147           0 : nsOfflineCachePendingUpdate::OnStateChange(nsIWebProgress* aWebProgress,
     148             :                                            nsIRequest *aRequest,
     149             :                                            uint32_t progressStateFlags,
     150             :                                            nsresult aStatus)
     151             : {
     152           0 :     if (mDidReleaseThis) {
     153           0 :         return NS_OK;
     154             :     }
     155           0 :     nsCOMPtr<nsIDOMDocument> updateDoc = do_QueryReferent(mDocument);
     156           0 :     if (!updateDoc) {
     157             :         // The document that scheduled this update has gone away,
     158             :         // we don't need to listen anymore.
     159           0 :         aWebProgress->RemoveProgressListener(this);
     160           0 :         MOZ_ASSERT(!mDidReleaseThis);
     161           0 :         mDidReleaseThis = true;
     162           0 :         NS_RELEASE_THIS();
     163           0 :         return NS_OK;
     164             :     }
     165             : 
     166           0 :     if (!(progressStateFlags & STATE_STOP)) {
     167           0 :         return NS_OK;
     168             :     }
     169             : 
     170           0 :     nsCOMPtr<mozIDOMWindowProxy> windowProxy;
     171           0 :     aWebProgress->GetDOMWindow(getter_AddRefs(windowProxy));
     172           0 :     if (!windowProxy) return NS_OK;
     173             : 
     174           0 :     auto* outerWindow = nsPIDOMWindowOuter::From(windowProxy);
     175           0 :     nsPIDOMWindowInner* innerWindow = outerWindow->GetCurrentInnerWindow();
     176             : 
     177           0 :     nsCOMPtr<nsIDocument> progressDoc = outerWindow->GetDoc();
     178           0 :     if (!progressDoc) return NS_OK;
     179             : 
     180           0 :     if (!SameCOMIdentity(progressDoc, updateDoc)) {
     181           0 :         return NS_OK;
     182             :     }
     183             : 
     184           0 :     LOG(("nsOfflineCachePendingUpdate::OnStateChange [%p, doc=%p]",
     185             :          this, progressDoc.get()));
     186             : 
     187             :     // Only schedule the update if the document loaded successfully
     188           0 :     if (NS_SUCCEEDED(aStatus)) {
     189           0 :         nsCOMPtr<nsIOfflineCacheUpdate> update;
     190           0 :         mService->Schedule(mManifestURI, mDocumentURI, mLoadingPrincipal, updateDoc, innerWindow,
     191           0 :                            nullptr, getter_AddRefs(update));
     192           0 :         if (mDidReleaseThis) {
     193           0 :             return NS_OK;
     194             :         }
     195             :     }
     196             : 
     197           0 :     aWebProgress->RemoveProgressListener(this);
     198           0 :     MOZ_ASSERT(!mDidReleaseThis);
     199           0 :     mDidReleaseThis = true;
     200           0 :     NS_RELEASE_THIS();
     201             : 
     202           0 :     return NS_OK;
     203             : }
     204             : 
     205             : NS_IMETHODIMP
     206           0 : nsOfflineCachePendingUpdate::OnLocationChange(nsIWebProgress* aWebProgress,
     207             :                                               nsIRequest* aRequest,
     208             :                                               nsIURI *location,
     209             :                                               uint32_t aFlags)
     210             : {
     211           0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     212           0 :     return NS_OK;
     213             : }
     214             : 
     215             : NS_IMETHODIMP
     216           0 : nsOfflineCachePendingUpdate::OnStatusChange(nsIWebProgress* aWebProgress,
     217             :                                             nsIRequest* aRequest,
     218             :                                             nsresult aStatus,
     219             :                                             const char16_t* aMessage)
     220             : {
     221           0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     222           0 :     return NS_OK;
     223             : }
     224             : 
     225             : NS_IMETHODIMP
     226           0 : nsOfflineCachePendingUpdate::OnSecurityChange(nsIWebProgress *aWebProgress,
     227             :                                               nsIRequest *aRequest,
     228             :                                               uint32_t state)
     229             : {
     230           0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     231           0 :     return NS_OK;
     232             : }
     233             : 
     234             : //-----------------------------------------------------------------------------
     235             : // nsOfflineCacheUpdateService::nsISupports
     236             : //-----------------------------------------------------------------------------
     237             : 
     238          10 : NS_IMPL_ISUPPORTS(nsOfflineCacheUpdateService,
     239             :                   nsIOfflineCacheUpdateService,
     240             :                   nsIObserver,
     241             :                   nsISupportsWeakReference)
     242             : 
     243             : //-----------------------------------------------------------------------------
     244             : // nsOfflineCacheUpdateService <public>
     245             : //-----------------------------------------------------------------------------
     246             : 
     247           1 : nsOfflineCacheUpdateService::nsOfflineCacheUpdateService()
     248             :     : mDisabled(false)
     249             :     , mUpdateRunning(false)
     250           1 :     , mLowFreeSpace(false)
     251             : {
     252           1 :     MOZ_ASSERT(NS_IsMainThread());
     253             :     Preferences::AddBoolVarCache(&sAllowOfflineCache,
     254             :                                  "browser.cache.offline.enable",
     255           1 :                                  true);
     256           1 : }
     257             : 
     258           0 : nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
     259             : {
     260           0 :     gOfflineCacheUpdateService = nullptr;
     261           0 : }
     262             : 
     263             : nsresult
     264           1 : nsOfflineCacheUpdateService::Init()
     265             : {
     266             :     // Observe xpcom-shutdown event
     267             :     nsCOMPtr<nsIObserverService> observerService =
     268           2 :       mozilla::services::GetObserverService();
     269           1 :     if (!observerService)
     270           0 :       return NS_ERROR_FAILURE;
     271             : 
     272           2 :     nsresult rv = observerService->AddObserver(this,
     273             :                                                NS_XPCOM_SHUTDOWN_OBSERVER_ID,
     274           2 :                                                true);
     275           1 :     NS_ENSURE_SUCCESS(rv, rv);
     276             : 
     277             :     // Get the current status of the disk in terms of free space and observe
     278             :     // low device storage notifications.
     279             :     nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcherService =
     280           2 :       do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
     281           1 :     if (diskSpaceWatcherService) {
     282           0 :       diskSpaceWatcherService->GetIsDiskFull(&mLowFreeSpace);
     283             :     } else {
     284           1 :       NS_WARNING("Could not get disk status from nsIDiskSpaceWatcher");
     285             :     }
     286             : 
     287           1 :     rv = observerService->AddObserver(this, "disk-space-watcher", false);
     288           1 :     NS_ENSURE_SUCCESS(rv, rv);
     289             : 
     290           1 :     gOfflineCacheUpdateService = this;
     291             : 
     292           1 :     return NS_OK;
     293             : }
     294             : 
     295             : /* static */
     296             : nsOfflineCacheUpdateService *
     297           1 : nsOfflineCacheUpdateService::GetInstance()
     298             : {
     299           1 :     if (!gOfflineCacheUpdateService) {
     300           1 :         gOfflineCacheUpdateService = new nsOfflineCacheUpdateService();
     301           1 :         if (!gOfflineCacheUpdateService)
     302           0 :             return nullptr;
     303           1 :         NS_ADDREF(gOfflineCacheUpdateService);
     304           1 :         nsresult rv = gOfflineCacheUpdateService->Init();
     305           1 :         if (NS_FAILED(rv)) {
     306           0 :             NS_RELEASE(gOfflineCacheUpdateService);
     307           0 :             return nullptr;
     308             :         }
     309           1 :         return gOfflineCacheUpdateService;
     310             :     }
     311             : 
     312           0 :     NS_ADDREF(gOfflineCacheUpdateService);
     313             : 
     314           0 :     return gOfflineCacheUpdateService;
     315             : }
     316             : 
     317             : /* static */
     318             : nsOfflineCacheUpdateService *
     319           0 : nsOfflineCacheUpdateService::EnsureService()
     320             : {
     321           0 :     if (!gOfflineCacheUpdateService) {
     322             :         // Make the service manager hold a long-lived reference to the service
     323             :         nsCOMPtr<nsIOfflineCacheUpdateService> service =
     324           0 :             do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
     325             :     }
     326             : 
     327           0 :     return gOfflineCacheUpdateService;
     328             : }
     329             : 
     330             : nsresult
     331           0 : nsOfflineCacheUpdateService::ScheduleUpdate(nsOfflineCacheUpdate *aUpdate)
     332             : {
     333           0 :     LOG(("nsOfflineCacheUpdateService::Schedule [%p, update=%p]",
     334             :          this, aUpdate));
     335             : 
     336           0 :     aUpdate->SetOwner(this);
     337             : 
     338           0 :     mUpdates.AppendElement(aUpdate);
     339           0 :     ProcessNextUpdate();
     340             : 
     341           0 :     return NS_OK;
     342             : }
     343             : 
     344             : NS_IMETHODIMP
     345           0 : nsOfflineCacheUpdateService::ScheduleOnDocumentStop(nsIURI *aManifestURI,
     346             :                                                     nsIURI *aDocumentURI,
     347             :                                                     nsIPrincipal* aLoadingPrincipal,
     348             :                                                     nsIDOMDocument *aDocument)
     349             : {
     350           0 :     LOG(("nsOfflineCacheUpdateService::ScheduleOnDocumentStop [%p, manifestURI=%p, documentURI=%p doc=%p]",
     351             :          this, aManifestURI, aDocumentURI, aDocument));
     352             : 
     353           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
     354           0 :     nsCOMPtr<nsIWebProgress> progress = do_QueryInterface(doc->GetContainer());
     355           0 :     NS_ENSURE_TRUE(progress, NS_ERROR_INVALID_ARG);
     356             : 
     357             :     // Proceed with cache update
     358             :     RefPtr<nsOfflineCachePendingUpdate> update =
     359             :         new nsOfflineCachePendingUpdate(this, aManifestURI, aDocumentURI,
     360           0 :                                         aLoadingPrincipal, aDocument);
     361           0 :     NS_ENSURE_TRUE(update, NS_ERROR_OUT_OF_MEMORY);
     362             : 
     363           0 :     nsresult rv = progress->AddProgressListener
     364           0 :         (update, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
     365           0 :     NS_ENSURE_SUCCESS(rv, rv);
     366             : 
     367             :     // The update will release when it has scheduled itself.
     368           0 :     Unused << update.forget();
     369             : 
     370           0 :     return NS_OK;
     371             : }
     372             : 
     373             : nsresult
     374           0 : nsOfflineCacheUpdateService::UpdateFinished(nsOfflineCacheUpdate *aUpdate)
     375             : {
     376           0 :     LOG(("nsOfflineCacheUpdateService::UpdateFinished [%p, update=%p]",
     377             :          this, aUpdate));
     378             : 
     379           0 :     NS_ASSERTION(mUpdates.Length() > 0 &&
     380             :                  mUpdates[0] == aUpdate, "Unknown update completed");
     381             : 
     382             :     // keep this item alive until we're done notifying observers
     383           0 :     RefPtr<nsOfflineCacheUpdate> update = mUpdates[0];
     384             :     Unused << update;
     385           0 :     mUpdates.RemoveElementAt(0);
     386           0 :     mUpdateRunning = false;
     387             : 
     388           0 :     ProcessNextUpdate();
     389             : 
     390           0 :     return NS_OK;
     391             : }
     392             : 
     393             : //-----------------------------------------------------------------------------
     394             : // nsOfflineCacheUpdateService <private>
     395             : //-----------------------------------------------------------------------------
     396             : 
     397             : nsresult
     398           0 : nsOfflineCacheUpdateService::ProcessNextUpdate()
     399             : {
     400           0 :     LOG(("nsOfflineCacheUpdateService::ProcessNextUpdate [%p, num=%" PRIuSIZE "]",
     401             :          this, mUpdates.Length()));
     402             : 
     403           0 :     if (mDisabled)
     404           0 :         return NS_ERROR_ABORT;
     405             : 
     406           0 :     if (mUpdateRunning)
     407           0 :         return NS_OK;
     408             : 
     409           0 :     if (mUpdates.Length() > 0) {
     410           0 :         mUpdateRunning = true;
     411             :         // Canceling the update before Begin() call will make the update
     412             :         // asynchronously finish with an error.
     413           0 :         if (mLowFreeSpace) {
     414           0 :             mUpdates[0]->Cancel();
     415             :         }
     416           0 :         return mUpdates[0]->Begin();
     417             :     }
     418             : 
     419           0 :     return NS_OK;
     420             : }
     421             : 
     422             : //-----------------------------------------------------------------------------
     423             : // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
     424             : //-----------------------------------------------------------------------------
     425             : 
     426             : NS_IMETHODIMP
     427           0 : nsOfflineCacheUpdateService::GetNumUpdates(uint32_t *aNumUpdates)
     428             : {
     429           0 :     LOG(("nsOfflineCacheUpdateService::GetNumUpdates [%p]", this));
     430             : 
     431           0 :     *aNumUpdates = mUpdates.Length();
     432           0 :     return NS_OK;
     433             : }
     434             : 
     435             : NS_IMETHODIMP
     436           0 : nsOfflineCacheUpdateService::GetUpdate(uint32_t aIndex,
     437             :                                        nsIOfflineCacheUpdate **aUpdate)
     438             : {
     439           0 :     LOG(("nsOfflineCacheUpdateService::GetUpdate [%p, %d]", this, aIndex));
     440             : 
     441           0 :     if (aIndex < mUpdates.Length()) {
     442           0 :         NS_ADDREF(*aUpdate = mUpdates[aIndex]);
     443             :     } else {
     444           0 :         *aUpdate = nullptr;
     445             :     }
     446             : 
     447           0 :     return NS_OK;
     448             : }
     449             : 
     450             : nsresult
     451           0 : nsOfflineCacheUpdateService::FindUpdate(nsIURI *aManifestURI,
     452             :                                         nsACString const &aOriginSuffix,
     453             :                                         nsIFile *aCustomProfileDir,
     454             :                                         nsOfflineCacheUpdate **aUpdate)
     455             : {
     456             :     nsresult rv;
     457             : 
     458             :     nsCOMPtr<nsIApplicationCacheService> cacheService =
     459           0 :         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
     460           0 :     NS_ENSURE_SUCCESS(rv, rv);
     461             : 
     462           0 :     nsAutoCString groupID;
     463           0 :     rv = cacheService->BuildGroupIDForSuffix(aManifestURI, aOriginSuffix, groupID);
     464           0 :     NS_ENSURE_SUCCESS(rv, rv);
     465             : 
     466           0 :     RefPtr<nsOfflineCacheUpdate> update;
     467           0 :     for (uint32_t i = 0; i < mUpdates.Length(); i++) {
     468           0 :         update = mUpdates[i];
     469             : 
     470             :         bool partial;
     471           0 :         rv = update->GetPartial(&partial);
     472           0 :         NS_ENSURE_SUCCESS(rv, rv);
     473             : 
     474           0 :         if (partial) {
     475             :             // Partial updates aren't considered
     476           0 :             continue;
     477             :         }
     478             : 
     479           0 :         if (update->IsForGroupID(groupID) && update->IsForProfile(aCustomProfileDir)) {
     480           0 :             update.swap(*aUpdate);
     481           0 :             return NS_OK;
     482             :         }
     483             :     }
     484             : 
     485           0 :     return NS_ERROR_NOT_AVAILABLE;
     486             : }
     487             : 
     488             : nsresult
     489           0 : nsOfflineCacheUpdateService::Schedule(nsIURI *aManifestURI,
     490             :                                       nsIURI *aDocumentURI,
     491             :                                       nsIPrincipal* aLoadingPrincipal,
     492             :                                       nsIDOMDocument *aDocument,
     493             :                                       nsPIDOMWindowInner* aWindow,
     494             :                                       nsIFile* aCustomProfileDir,
     495             :                                       nsIOfflineCacheUpdate **aUpdate)
     496             : {
     497           0 :     nsCOMPtr<nsIOfflineCacheUpdate> update;
     498           0 :     if (GeckoProcessType_Default != XRE_GetProcessType()) {
     499           0 :         update = new OfflineCacheUpdateChild(aWindow);
     500             :     }
     501             :     else {
     502           0 :         update = new OfflineCacheUpdateGlue();
     503             :     }
     504             : 
     505             :     nsresult rv;
     506             : 
     507           0 :     if (aWindow) {
     508             :       // Ensure there is window.applicationCache object that is
     509             :       // responsible for association of the new applicationCache
     510             :       // with the corresponding document.  Just ignore the result.
     511             :       nsCOMPtr<nsIDOMOfflineResourceList> appCacheWindowObject =
     512           0 :           aWindow->GetApplicationCache();
     513             :     }
     514             : 
     515           0 :     rv = update->Init(aManifestURI, aDocumentURI, aLoadingPrincipal, aDocument,
     516           0 :                       aCustomProfileDir);
     517           0 :     NS_ENSURE_SUCCESS(rv, rv);
     518             : 
     519           0 :     rv = update->Schedule();
     520           0 :     NS_ENSURE_SUCCESS(rv, rv);
     521             : 
     522           0 :     NS_ADDREF(*aUpdate = update);
     523             : 
     524           0 :     return NS_OK;
     525             : }
     526             : 
     527             : NS_IMETHODIMP
     528           0 : nsOfflineCacheUpdateService::ScheduleUpdate(nsIURI *aManifestURI,
     529             :                                             nsIURI *aDocumentURI,
     530             :                                             nsIPrincipal* aLoadingPrincipal,
     531             :                                             mozIDOMWindow* aWindow,
     532             :                                             nsIOfflineCacheUpdate **aUpdate)
     533             : {
     534           0 :     return Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, nullptr,
     535           0 :                     nsPIDOMWindowInner::From(aWindow), nullptr, aUpdate);
     536             : }
     537             : 
     538             : NS_IMETHODIMP
     539           0 : nsOfflineCacheUpdateService::ScheduleAppUpdate(nsIURI *aManifestURI,
     540             :                                                nsIURI *aDocumentURI,
     541             :                                                nsIPrincipal* aLoadingPrincipal,
     542             :                                                nsIFile *aProfileDir,
     543             :                                                nsIOfflineCacheUpdate **aUpdate)
     544             : {
     545             :     return Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, nullptr, nullptr,
     546           0 :                     aProfileDir, aUpdate);
     547             : }
     548             : 
     549           0 : NS_IMETHODIMP nsOfflineCacheUpdateService::CheckForUpdate(nsIURI *aManifestURI,
     550             :                                                           nsIPrincipal* aLoadingPrincipal,
     551             :                                                           nsIObserver *aObserver)
     552             : {
     553           0 :     if (GeckoProcessType_Default != XRE_GetProcessType()) {
     554             :         // Not intended to support this on child processes
     555           0 :         return NS_ERROR_NOT_IMPLEMENTED;
     556             :     }
     557             : 
     558           0 :     nsCOMPtr<nsIOfflineCacheUpdate> update = new OfflineCacheUpdateGlue();
     559             : 
     560             :     nsresult rv;
     561             : 
     562           0 :     rv = update->InitForUpdateCheck(aManifestURI, aLoadingPrincipal, aObserver);
     563           0 :     NS_ENSURE_SUCCESS(rv, rv);
     564             : 
     565           0 :     rv = update->Schedule();
     566           0 :     NS_ENSURE_SUCCESS(rv, rv);
     567             : 
     568           0 :     return NS_OK;
     569             : }
     570             : 
     571             : //-----------------------------------------------------------------------------
     572             : // nsOfflineCacheUpdateService::nsIObserver
     573             : //-----------------------------------------------------------------------------
     574             : 
     575             : NS_IMETHODIMP
     576           0 : nsOfflineCacheUpdateService::Observe(nsISupports     *aSubject,
     577             :                                      const char      *aTopic,
     578             :                                      const char16_t *aData)
     579             : {
     580           0 :     if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     581           0 :         if (mUpdates.Length() > 0)
     582           0 :             mUpdates[0]->Cancel();
     583           0 :         mDisabled = true;
     584             :     }
     585             : 
     586           0 :     if (!strcmp(aTopic, "disk-space-watcher")) {
     587           0 :         if (NS_LITERAL_STRING("full").Equals(aData)) {
     588           0 :             mLowFreeSpace = true;
     589           0 :             for (uint32_t i = 0; i < mUpdates.Length(); i++) {
     590           0 :                 mUpdates[i]->Cancel();
     591             :             }
     592           0 :         } else if (NS_LITERAL_STRING("free").Equals(aData)) {
     593           0 :             mLowFreeSpace = false;
     594             :         }
     595             :     }
     596             : 
     597           0 :     return NS_OK;
     598             : }
     599             : 
     600             : //-----------------------------------------------------------------------------
     601             : // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
     602             : //-----------------------------------------------------------------------------
     603             : 
     604             : static nsresult
     605           1 : OfflineAppPermForPrincipal(nsIPrincipal *aPrincipal,
     606             :                            nsIPrefBranch *aPrefBranch,
     607             :                            bool pinned,
     608             :                            bool *aAllowed)
     609             : {
     610           1 :     *aAllowed = false;
     611             : 
     612           1 :     if (!sAllowOfflineCache) {
     613           0 :         return NS_OK;
     614             :     }
     615             : 
     616           1 :     if (!aPrincipal)
     617           0 :         return NS_ERROR_INVALID_ARG;
     618             : 
     619           2 :     nsCOMPtr<nsIURI> uri;
     620           1 :     aPrincipal->GetURI(getter_AddRefs(uri));
     621             : 
     622           1 :     if (!uri)
     623           0 :         return NS_OK;
     624             : 
     625           2 :     nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
     626           1 :     if (!innerURI)
     627           0 :         return NS_OK;
     628             : 
     629             :     // only http and https applications can use offline APIs.
     630             :     bool match;
     631           1 :     nsresult rv = innerURI->SchemeIs("http", &match);
     632           1 :     NS_ENSURE_SUCCESS(rv, rv);
     633             : 
     634           1 :     if (!match) {
     635           0 :         rv = innerURI->SchemeIs("https", &match);
     636           0 :         NS_ENSURE_SUCCESS(rv, rv);
     637           0 :         if (!match) {
     638           0 :             return NS_OK;
     639             :         }
     640             :     }
     641             : 
     642           2 :     nsAutoCString domain;
     643           1 :     rv = innerURI->GetAsciiHost(domain);
     644           1 :     NS_ENSURE_SUCCESS(rv, rv);
     645             : 
     646           1 :     if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) {
     647           0 :         *aAllowed = true;
     648           0 :         return NS_OK;
     649             :     }
     650             : 
     651             :     nsCOMPtr<nsIPermissionManager> permissionManager =
     652           2 :         services::GetPermissionManager();
     653           1 :     if (!permissionManager) {
     654           0 :         return NS_OK;
     655             :     }
     656             : 
     657             :     uint32_t perm;
     658           1 :     const char *permName = pinned ? "pin-app" : "offline-app";
     659           1 :     permissionManager->TestExactPermissionFromPrincipal(aPrincipal, permName, &perm);
     660             : 
     661           2 :     if (perm == nsIPermissionManager::ALLOW_ACTION ||
     662           1 :         perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN) {
     663           0 :         *aAllowed = true;
     664             :     }
     665             : 
     666             :     // offline-apps.allow_by_default is now effective at the cache selection
     667             :     // algorithm code (nsContentSink).
     668             : 
     669           1 :     return NS_OK;
     670             : }
     671             : 
     672             : NS_IMETHODIMP
     673           1 : nsOfflineCacheUpdateService::OfflineAppAllowed(nsIPrincipal *aPrincipal,
     674             :                                                nsIPrefBranch *aPrefBranch,
     675             :                                                bool *aAllowed)
     676             : {
     677           1 :     return OfflineAppPermForPrincipal(aPrincipal, aPrefBranch, false, aAllowed);
     678             : }
     679             : 
     680             : NS_IMETHODIMP
     681           0 : nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI *aURI,
     682             :                                                      nsIPrefBranch *aPrefBranch,
     683             :                                                      bool *aAllowed)
     684             : {
     685           0 :     OriginAttributes attrs;
     686             :     nsCOMPtr<nsIPrincipal> principal =
     687           0 :         BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
     688           0 :     return OfflineAppPermForPrincipal(principal, aPrefBranch, false, aAllowed);
     689             : }
     690             : 
     691             : nsresult
     692           0 : nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI,
     693             :                                                     nsIPrefBranch *aPrefBranch,
     694             :                                                     bool *aPinned)
     695             : {
     696           0 :     OriginAttributes attrs;
     697             :     nsCOMPtr<nsIPrincipal> principal =
     698           0 :         BasePrincipal::CreateCodebasePrincipal(aDocumentURI, attrs);
     699           0 :     return OfflineAppPermForPrincipal(principal, aPrefBranch, true, aPinned);
     700             : }
     701             : 
     702             : NS_IMETHODIMP
     703           0 : nsOfflineCacheUpdateService::AllowOfflineApp(nsIPrincipal *aPrincipal)
     704             : {
     705             :     nsresult rv;
     706             : 
     707           0 :     if (!sAllowOfflineCache) {
     708           0 :         return NS_ERROR_NOT_AVAILABLE;
     709             :     }
     710             : 
     711           0 :     if (GeckoProcessType_Default != XRE_GetProcessType()) {
     712           0 :         ContentChild* child = ContentChild::GetSingleton();
     713             : 
     714           0 :         if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) {
     715           0 :             return NS_ERROR_FAILURE;
     716             :         }
     717             : 
     718           0 :         nsAutoCString domain;
     719           0 :         rv = aPrincipal->GetBaseDomain(domain);
     720           0 :         NS_ENSURE_SUCCESS(rv, rv);
     721             : 
     722           0 :         nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain);
     723             :     }
     724             :     else {
     725             :         nsCOMPtr<nsIPermissionManager> permissionManager =
     726           0 :             services::GetPermissionManager();
     727           0 :         if (!permissionManager)
     728           0 :             return NS_ERROR_NOT_AVAILABLE;
     729             : 
     730           0 :         rv = permissionManager->AddFromPrincipal(
     731             :             aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION,
     732           0 :             nsIPermissionManager::EXPIRE_NEVER, 0);
     733           0 :         NS_ENSURE_SUCCESS(rv, rv);
     734             :     }
     735             : 
     736           0 :     return NS_OK;
     737             : }

Generated by: LCOV version 1.13