uriloader/prefetch/nsOfflineCacheUpdateService.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     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/. */
     6 #if defined(MOZ_LOGGING)
     7 #define FORCE_PR_LOG
     8 #endif
    10 #include "OfflineCacheUpdateChild.h"
    11 #include "OfflineCacheUpdateParent.h"
    12 #include "nsXULAppAPI.h"
    13 #include "OfflineCacheUpdateGlue.h"
    14 #include "nsOfflineCacheUpdate.h"
    16 #include "nsCPrefetchService.h"
    17 #include "nsCURILoader.h"
    18 #include "nsIApplicationCacheContainer.h"
    19 #include "nsIApplicationCacheChannel.h"
    20 #include "nsIApplicationCacheService.h"
    21 #include "nsICache.h"
    22 #include "nsICacheService.h"
    23 #include "nsICacheSession.h"
    24 #include "nsICachingChannel.h"
    25 #include "nsIContent.h"
    26 #include "nsIDocShell.h"
    27 #include "nsIDocumentLoader.h"
    28 #include "nsIDOMElement.h"
    29 #include "nsIDOMWindow.h"
    30 #include "nsIDOMOfflineResourceList.h"
    31 #include "nsIDocument.h"
    32 #include "nsIObserverService.h"
    33 #include "nsIURL.h"
    34 #include "nsIWebProgress.h"
    35 #include "nsIWebNavigation.h"
    36 #include "nsICryptoHash.h"
    37 #include "nsICacheEntryDescriptor.h"
    38 #include "nsIPermissionManager.h"
    39 #include "nsIPrincipal.h"
    40 #include "nsIScriptSecurityManager.h"
    41 #include "nsNetCID.h"
    42 #include "nsNetUtil.h"
    43 #include "nsServiceManagerUtils.h"
    44 #include "nsStreamUtils.h"
    45 #include "nsThreadUtils.h"
    46 #include "nsProxyRelease.h"
    47 #include "prlog.h"
    48 #include "nsIAsyncVerifyRedirectCallback.h"
    49 #include "mozilla/Preferences.h"
    50 #include "mozilla/Attributes.h"
    51 #include "mozilla/unused.h"
    52 #include "nsIDiskSpaceWatcher.h"
    53 #include "nsIDocShell.h"
    54 #include "nsIDocShellTreeItem.h"
    55 #include "nsIDocShellTreeOwner.h"
    56 #include "mozilla/dom/TabChild.h"
    57 #include "mozilla/dom/PermissionMessageUtils.h"
    58 #include "nsContentUtils.h"
    59 #include "mozilla/unused.h"
    61 using namespace mozilla;
    62 using namespace mozilla::dom;
    64 static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr;
    66 nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::mAllowedDomains = nullptr;
    68 nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::AllowedDomains()
    69 {
    70     if (!mAllowedDomains)
    71         mAllowedDomains = new nsTHashtable<nsCStringHashKey>();
    73     return mAllowedDomains;
    74 }
    77 typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent;
    78 typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild;
    79 typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue;
    81 #if defined(PR_LOGGING)
    82 //
    83 // To enable logging (see prlog.h for full details):
    84 //
    85 //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
    86 //    set NSPR_LOG_FILE=offlineupdate.log
    87 //
    88 // this enables PR_LOG_ALWAYS level information and places all output in
    89 // the file offlineupdate.log
    90 //
    91 PRLogModuleInfo *gOfflineCacheUpdateLog;
    92 #endif
    94 #undef LOG
    95 #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args)
    97 #undef LOG_ENABLED
    98 #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4)
   100 namespace { // anon
   102 nsresult
   103 GetAppIDAndInBrowserFromWindow(nsIDOMWindow *aWindow,
   104                                uint32_t *aAppId,
   105                                bool *aInBrowser)
   106 {
   107     *aAppId = NECKO_NO_APP_ID;
   108     *aInBrowser = false;
   110     if (!aWindow) {
   111         return NS_OK;
   112     }
   114     nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aWindow);
   115     if (!loadContext) {
   116         return NS_OK;
   117     }
   119     nsresult rv;
   121     rv = loadContext->GetAppId(aAppId);
   122     NS_ENSURE_SUCCESS(rv, rv);
   124     rv = loadContext->GetIsInBrowserElement(aInBrowser);
   125     NS_ENSURE_SUCCESS(rv, rv);
   127     return NS_OK;
   128 }
   130 } // anon
   132 //-----------------------------------------------------------------------------
   133 // nsOfflineCachePendingUpdate
   134 //-----------------------------------------------------------------------------
   136 class nsOfflineCachePendingUpdate MOZ_FINAL : public nsIWebProgressListener
   137                                             , public nsSupportsWeakReference
   138 {
   139 public:
   140     NS_DECL_ISUPPORTS
   141     NS_DECL_NSIWEBPROGRESSLISTENER
   143     nsOfflineCachePendingUpdate(nsOfflineCacheUpdateService *aService,
   144                                 nsIURI *aManifestURI,
   145                                 nsIURI *aDocumentURI,
   146                                 nsIDOMDocument *aDocument)
   147         : mService(aService)
   148         , mManifestURI(aManifestURI)
   149         , mDocumentURI(aDocumentURI)
   150         , mDidReleaseThis(false)
   151         {
   152             mDocument = do_GetWeakReference(aDocument);
   153         }
   155 private:
   156     nsRefPtr<nsOfflineCacheUpdateService> mService;
   157     nsCOMPtr<nsIURI> mManifestURI;
   158     nsCOMPtr<nsIURI> mDocumentURI;
   159     nsCOMPtr<nsIWeakReference> mDocument;
   160     bool mDidReleaseThis;
   161 };
   163 NS_IMPL_ISUPPORTS(nsOfflineCachePendingUpdate,
   164                   nsIWebProgressListener,
   165                   nsISupportsWeakReference)
   167 //-----------------------------------------------------------------------------
   168 // nsOfflineCacheUpdateService::nsIWebProgressListener
   169 //-----------------------------------------------------------------------------
   171 NS_IMETHODIMP
   172 nsOfflineCachePendingUpdate::OnProgressChange(nsIWebProgress *aProgress,
   173                                               nsIRequest *aRequest,
   174                                               int32_t curSelfProgress,
   175                                               int32_t maxSelfProgress,
   176                                               int32_t curTotalProgress,
   177                                               int32_t maxTotalProgress)
   178 {
   179     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   180     return NS_OK;
   181 }
   183 NS_IMETHODIMP
   184 nsOfflineCachePendingUpdate::OnStateChange(nsIWebProgress* aWebProgress,
   185                                            nsIRequest *aRequest,
   186                                            uint32_t progressStateFlags,
   187                                            nsresult aStatus)
   188 {
   189     if (mDidReleaseThis) {
   190         return NS_OK;
   191     }
   192     nsCOMPtr<nsIDOMDocument> updateDoc = do_QueryReferent(mDocument);
   193     if (!updateDoc) {
   194         // The document that scheduled this update has gone away,
   195         // we don't need to listen anymore.
   196         aWebProgress->RemoveProgressListener(this);
   197         MOZ_ASSERT(!mDidReleaseThis);
   198         mDidReleaseThis = true;
   199         NS_RELEASE_THIS();
   200         return NS_OK;
   201     }
   203     if (!(progressStateFlags & STATE_STOP)) {
   204         return NS_OK;
   205     }
   207     nsCOMPtr<nsIDOMWindow> window;
   208     aWebProgress->GetDOMWindow(getter_AddRefs(window));
   209     if (!window) return NS_OK;
   211     nsCOMPtr<nsIDOMDocument> progressDoc;
   212     window->GetDocument(getter_AddRefs(progressDoc));
   213     if (!progressDoc) return NS_OK;
   215     if (!SameCOMIdentity(progressDoc, updateDoc)) {
   216         return NS_OK;
   217     }
   219     LOG(("nsOfflineCachePendingUpdate::OnStateChange [%p, doc=%p]",
   220          this, progressDoc.get()));
   222     // Only schedule the update if the document loaded successfully
   223     if (NS_SUCCEEDED(aStatus)) {
   224         // Get extended origin attributes
   225         uint32_t appId;
   226         bool isInBrowserElement;
   227         nsresult rv = GetAppIDAndInBrowserFromWindow(window, &appId, &isInBrowserElement);
   228         NS_ENSURE_SUCCESS(rv, rv);
   230         nsCOMPtr<nsIOfflineCacheUpdate> update;
   231         mService->Schedule(mManifestURI, mDocumentURI,
   232                            updateDoc, window, nullptr,
   233                            appId, isInBrowserElement, getter_AddRefs(update));
   234         if (mDidReleaseThis) {
   235             return NS_OK;
   236         }
   237     }
   239     aWebProgress->RemoveProgressListener(this);
   240     MOZ_ASSERT(!mDidReleaseThis);
   241     mDidReleaseThis = true;
   242     NS_RELEASE_THIS();
   244     return NS_OK;
   245 }
   247 NS_IMETHODIMP
   248 nsOfflineCachePendingUpdate::OnLocationChange(nsIWebProgress* aWebProgress,
   249                                               nsIRequest* aRequest,
   250                                               nsIURI *location,
   251                                               uint32_t aFlags)
   252 {
   253     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   254     return NS_OK;
   255 }
   257 NS_IMETHODIMP
   258 nsOfflineCachePendingUpdate::OnStatusChange(nsIWebProgress* aWebProgress,
   259                                             nsIRequest* aRequest,
   260                                             nsresult aStatus,
   261                                             const char16_t* aMessage)
   262 {
   263     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   264     return NS_OK;
   265 }
   267 NS_IMETHODIMP
   268 nsOfflineCachePendingUpdate::OnSecurityChange(nsIWebProgress *aWebProgress,
   269                                               nsIRequest *aRequest,
   270                                               uint32_t state)
   271 {
   272     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   273     return NS_OK;
   274 }
   276 //-----------------------------------------------------------------------------
   277 // nsOfflineCacheUpdateService::nsISupports
   278 //-----------------------------------------------------------------------------
   280 NS_IMPL_ISUPPORTS(nsOfflineCacheUpdateService,
   281                   nsIOfflineCacheUpdateService,
   282                   nsIObserver,
   283                   nsISupportsWeakReference)
   285 //-----------------------------------------------------------------------------
   286 // nsOfflineCacheUpdateService <public>
   287 //-----------------------------------------------------------------------------
   289 nsOfflineCacheUpdateService::nsOfflineCacheUpdateService()
   290     : mDisabled(false)
   291     , mUpdateRunning(false)
   292     , mLowFreeSpace(false)
   293 {
   294 }
   296 nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
   297 {
   298     gOfflineCacheUpdateService = nullptr;
   299 }
   301 nsresult
   302 nsOfflineCacheUpdateService::Init()
   303 {
   304 #if defined(PR_LOGGING)
   305     if (!gOfflineCacheUpdateLog)
   306         gOfflineCacheUpdateLog = PR_NewLogModule("nsOfflineCacheUpdate");
   307 #endif
   309     // Observe xpcom-shutdown event
   310     nsCOMPtr<nsIObserverService> observerService =
   311       mozilla::services::GetObserverService();
   312     if (!observerService)
   313       return NS_ERROR_FAILURE;
   315     nsresult rv = observerService->AddObserver(this,
   316                                                NS_XPCOM_SHUTDOWN_OBSERVER_ID,
   317                                                true);
   318     NS_ENSURE_SUCCESS(rv, rv);
   320     // Get the current status of the disk in terms of free space and observe
   321     // low device storage notifications.
   322     nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcherService =
   323       do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
   324     if (diskSpaceWatcherService) {
   325       diskSpaceWatcherService->GetIsDiskFull(&mLowFreeSpace);
   326     } else {
   327       NS_WARNING("Could not get disk status from nsIDiskSpaceWatcher");
   328     }
   330     rv = observerService->AddObserver(this, "disk-space-watcher", false);
   331     NS_ENSURE_SUCCESS(rv, rv);
   333     gOfflineCacheUpdateService = this;
   335     return NS_OK;
   336 }
   338 /* static */
   339 nsOfflineCacheUpdateService *
   340 nsOfflineCacheUpdateService::GetInstance()
   341 {
   342     if (!gOfflineCacheUpdateService) {
   343         gOfflineCacheUpdateService = new nsOfflineCacheUpdateService();
   344         if (!gOfflineCacheUpdateService)
   345             return nullptr;
   346         NS_ADDREF(gOfflineCacheUpdateService);
   347         nsresult rv = gOfflineCacheUpdateService->Init();
   348         if (NS_FAILED(rv)) {
   349             NS_RELEASE(gOfflineCacheUpdateService);
   350             return nullptr;
   351         }
   352         return gOfflineCacheUpdateService;
   353     }
   355     NS_ADDREF(gOfflineCacheUpdateService);
   357     return gOfflineCacheUpdateService;
   358 }
   360 /* static */
   361 nsOfflineCacheUpdateService *
   362 nsOfflineCacheUpdateService::EnsureService()
   363 {
   364     if (!gOfflineCacheUpdateService) {
   365         // Make the service manager hold a long-lived reference to the service
   366         nsCOMPtr<nsIOfflineCacheUpdateService> service =
   367             do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
   368     }
   370     return gOfflineCacheUpdateService;
   371 }
   373 nsresult
   374 nsOfflineCacheUpdateService::ScheduleUpdate(nsOfflineCacheUpdate *aUpdate)
   375 {
   376     LOG(("nsOfflineCacheUpdateService::Schedule [%p, update=%p]",
   377          this, aUpdate));
   379     aUpdate->SetOwner(this);
   381     mUpdates.AppendElement(aUpdate);
   382     ProcessNextUpdate();
   384     return NS_OK;
   385 }
   387 NS_IMETHODIMP
   388 nsOfflineCacheUpdateService::ScheduleOnDocumentStop(nsIURI *aManifestURI,
   389                                                     nsIURI *aDocumentURI,
   390                                                     nsIDOMDocument *aDocument)
   391 {
   392     LOG(("nsOfflineCacheUpdateService::ScheduleOnDocumentStop [%p, manifestURI=%p, documentURI=%p doc=%p]",
   393          this, aManifestURI, aDocumentURI, aDocument));
   395     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
   396     nsCOMPtr<nsIWebProgress> progress = do_QueryInterface(doc->GetContainer());
   397     NS_ENSURE_TRUE(progress, NS_ERROR_INVALID_ARG);
   399     // Proceed with cache update
   400     nsRefPtr<nsOfflineCachePendingUpdate> update =
   401         new nsOfflineCachePendingUpdate(this, aManifestURI,
   402                                         aDocumentURI, aDocument);
   403     NS_ENSURE_TRUE(update, NS_ERROR_OUT_OF_MEMORY);
   405     nsresult rv = progress->AddProgressListener
   406         (update, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
   407     NS_ENSURE_SUCCESS(rv, rv);
   409     // The update will release when it has scheduled itself.
   410     unused << update.forget();
   412     return NS_OK;
   413 }
   415 nsresult
   416 nsOfflineCacheUpdateService::UpdateFinished(nsOfflineCacheUpdate *aUpdate)
   417 {
   418     LOG(("nsOfflineCacheUpdateService::UpdateFinished [%p, update=%p]",
   419          this, aUpdate));
   421     NS_ASSERTION(mUpdates.Length() > 0 &&
   422                  mUpdates[0] == aUpdate, "Unknown update completed");
   424     // keep this item alive until we're done notifying observers
   425     nsRefPtr<nsOfflineCacheUpdate> update = mUpdates[0];
   426     mUpdates.RemoveElementAt(0);
   427     mUpdateRunning = false;
   429     ProcessNextUpdate();
   431     return NS_OK;
   432 }
   434 //-----------------------------------------------------------------------------
   435 // nsOfflineCacheUpdateService <private>
   436 //-----------------------------------------------------------------------------
   438 nsresult
   439 nsOfflineCacheUpdateService::ProcessNextUpdate()
   440 {
   441     LOG(("nsOfflineCacheUpdateService::ProcessNextUpdate [%p, num=%d]",
   442          this, mUpdates.Length()));
   444     if (mDisabled)
   445         return NS_ERROR_ABORT;
   447     if (mUpdateRunning)
   448         return NS_OK;
   450     if (mUpdates.Length() > 0) {
   451         mUpdateRunning = true;
   452         // Canceling the update before Begin() call will make the update
   453         // asynchronously finish with an error.
   454         if (mLowFreeSpace) {
   455             mUpdates[0]->Cancel();
   456         }
   457         return mUpdates[0]->Begin();
   458     }
   460     return NS_OK;
   461 }
   463 //-----------------------------------------------------------------------------
   464 // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
   465 //-----------------------------------------------------------------------------
   467 NS_IMETHODIMP
   468 nsOfflineCacheUpdateService::GetNumUpdates(uint32_t *aNumUpdates)
   469 {
   470     LOG(("nsOfflineCacheUpdateService::GetNumUpdates [%p]", this));
   472     *aNumUpdates = mUpdates.Length();
   473     return NS_OK;
   474 }
   476 NS_IMETHODIMP
   477 nsOfflineCacheUpdateService::GetUpdate(uint32_t aIndex,
   478                                        nsIOfflineCacheUpdate **aUpdate)
   479 {
   480     LOG(("nsOfflineCacheUpdateService::GetUpdate [%p, %d]", this, aIndex));
   482     if (aIndex < mUpdates.Length()) {
   483         NS_ADDREF(*aUpdate = mUpdates[aIndex]);
   484     } else {
   485         *aUpdate = nullptr;
   486     }
   488     return NS_OK;
   489 }
   491 nsresult
   492 nsOfflineCacheUpdateService::FindUpdate(nsIURI *aManifestURI,
   493                                         uint32_t aAppID,
   494                                         bool aInBrowser,
   495                                         nsOfflineCacheUpdate **aUpdate)
   496 {
   497     nsresult rv;
   499     nsCOMPtr<nsIApplicationCacheService> cacheService =
   500         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
   501     NS_ENSURE_SUCCESS(rv, rv);
   503     nsAutoCString groupID;
   504     rv = cacheService->BuildGroupIDForApp(aManifestURI,
   505                                           aAppID, aInBrowser,
   506                                           groupID);
   507     NS_ENSURE_SUCCESS(rv, rv);
   509     nsRefPtr<nsOfflineCacheUpdate> update;
   510     for (uint32_t i = 0; i < mUpdates.Length(); i++) {
   511         update = mUpdates[i];
   513         bool partial;
   514         rv = update->GetPartial(&partial);
   515         NS_ENSURE_SUCCESS(rv, rv);
   517         if (partial) {
   518             // Partial updates aren't considered
   519             continue;
   520         }
   522         if (update->IsForGroupID(groupID)) {
   523             update.swap(*aUpdate);
   524             return NS_OK;
   525         }
   526     }
   528     return NS_ERROR_NOT_AVAILABLE;
   529 }
   531 nsresult
   532 nsOfflineCacheUpdateService::Schedule(nsIURI *aManifestURI,
   533                                       nsIURI *aDocumentURI,
   534                                       nsIDOMDocument *aDocument,
   535                                       nsIDOMWindow* aWindow,
   536                                       nsIFile* aCustomProfileDir,
   537                                       uint32_t aAppID,
   538                                       bool aInBrowser,
   539                                       nsIOfflineCacheUpdate **aUpdate)
   540 {
   541     nsCOMPtr<nsIOfflineCacheUpdate> update;
   542     if (GeckoProcessType_Default != XRE_GetProcessType()) {
   543         update = new OfflineCacheUpdateChild(aWindow);
   544     }
   545     else {
   546         update = new OfflineCacheUpdateGlue();
   547     }
   549     nsresult rv;
   551     if (aWindow) {
   552       // Ensure there is window.applicationCache object that is
   553       // responsible for association of the new applicationCache
   554       // with the corresponding document.  Just ignore the result.
   555       nsCOMPtr<nsIDOMOfflineResourceList> appCacheWindowObject;
   556       aWindow->GetApplicationCache(getter_AddRefs(appCacheWindowObject));
   557     }
   559     rv = update->Init(aManifestURI, aDocumentURI, aDocument,
   560                       aCustomProfileDir, aAppID, aInBrowser);
   561     NS_ENSURE_SUCCESS(rv, rv);
   563     rv = update->Schedule();
   564     NS_ENSURE_SUCCESS(rv, rv);
   566     NS_ADDREF(*aUpdate = update);
   568     return NS_OK;
   569 }
   571 NS_IMETHODIMP
   572 nsOfflineCacheUpdateService::ScheduleUpdate(nsIURI *aManifestURI,
   573                                             nsIURI *aDocumentURI,
   574                                             nsIDOMWindow *aWindow,
   575                                             nsIOfflineCacheUpdate **aUpdate)
   576 {
   577     // Get extended origin attributes
   578     uint32_t appId;
   579     bool isInBrowser;
   580     nsresult rv = GetAppIDAndInBrowserFromWindow(aWindow, &appId, &isInBrowser);
   581     NS_ENSURE_SUCCESS(rv, rv);
   583     return Schedule(aManifestURI, aDocumentURI, nullptr, aWindow, nullptr,
   584                     appId, isInBrowser, aUpdate);
   585 }
   587 NS_IMETHODIMP
   588 nsOfflineCacheUpdateService::ScheduleAppUpdate(nsIURI *aManifestURI,
   589                                                nsIURI *aDocumentURI,
   590                                                uint32_t aAppID, bool aInBrowser,
   591                                                nsIFile *aProfileDir,
   592                                                nsIOfflineCacheUpdate **aUpdate)
   593 {
   594     return Schedule(aManifestURI, aDocumentURI, nullptr, nullptr, aProfileDir,
   595                     aAppID, aInBrowser, aUpdate);
   596 }
   598 NS_IMETHODIMP nsOfflineCacheUpdateService::CheckForUpdate(nsIURI *aManifestURI,
   599                                                           uint32_t aAppID,
   600                                                           bool aInBrowser,
   601                                                           nsIObserver *aObserver)
   602 {
   603     if (GeckoProcessType_Default != XRE_GetProcessType()) {
   604         // Not intended to support this on child processes
   605         return NS_ERROR_NOT_IMPLEMENTED;
   606     }
   608     nsCOMPtr<nsIOfflineCacheUpdate> update = new OfflineCacheUpdateGlue();
   610     nsresult rv;
   612     rv = update->InitForUpdateCheck(aManifestURI, aAppID, aInBrowser, aObserver);
   613     NS_ENSURE_SUCCESS(rv, rv);
   615     rv = update->Schedule();
   616     NS_ENSURE_SUCCESS(rv, rv);
   618     return NS_OK;
   619 }
   621 //-----------------------------------------------------------------------------
   622 // nsOfflineCacheUpdateService::nsIObserver
   623 //-----------------------------------------------------------------------------
   625 NS_IMETHODIMP
   626 nsOfflineCacheUpdateService::Observe(nsISupports     *aSubject,
   627                                      const char      *aTopic,
   628                                      const char16_t *aData)
   629 {
   630     if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   631         if (mUpdates.Length() > 0)
   632             mUpdates[0]->Cancel();
   633         mDisabled = true;
   634     }
   636     if (!strcmp(aTopic, "disk-space-watcher")) {
   637         if (NS_LITERAL_STRING("full").Equals(aData)) {
   638             mLowFreeSpace = true;
   639             for (uint32_t i = 0; i < mUpdates.Length(); i++) {
   640                 mUpdates[i]->Cancel();
   641             }
   642         } else if (NS_LITERAL_STRING("free").Equals(aData)) {
   643             mLowFreeSpace = false;
   644         }
   645     }
   647     return NS_OK;
   648 }
   650 //-----------------------------------------------------------------------------
   651 // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
   652 //-----------------------------------------------------------------------------
   654 static nsresult
   655 OfflineAppPermForPrincipal(nsIPrincipal *aPrincipal,
   656                            nsIPrefBranch *aPrefBranch,
   657                            bool pinned,
   658                            bool *aAllowed)
   659 {
   660     *aAllowed = false;
   662     if (!aPrincipal)
   663         return NS_ERROR_INVALID_ARG;
   665     nsCOMPtr<nsIURI> uri;
   666     aPrincipal->GetURI(getter_AddRefs(uri));
   668     if (!uri)
   669         return NS_OK;
   671     nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
   672     if (!innerURI)
   673         return NS_OK;
   675     // only http and https applications can use offline APIs.
   676     bool match;
   677     nsresult rv = innerURI->SchemeIs("http", &match);
   678     NS_ENSURE_SUCCESS(rv, rv);
   680     if (!match) {
   681         rv = innerURI->SchemeIs("https", &match);
   682         NS_ENSURE_SUCCESS(rv, rv);
   683         if (!match) {
   684             return NS_OK;
   685         }
   686     }
   688     nsAutoCString domain;
   689     rv = innerURI->GetAsciiHost(domain);
   690     NS_ENSURE_SUCCESS(rv, rv);
   692     if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) {
   693         *aAllowed = true;
   694         return NS_OK;
   695     }
   697     nsCOMPtr<nsIPermissionManager> permissionManager =
   698         do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   699     if (!permissionManager) {
   700         return NS_OK;
   701     }
   703     uint32_t perm;
   704     const char *permName = pinned ? "pin-app" : "offline-app";
   705     permissionManager->TestExactPermissionFromPrincipal(aPrincipal, permName, &perm);
   707     if (perm == nsIPermissionManager::ALLOW_ACTION ||
   708         perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN) {
   709         *aAllowed = true;
   710     }
   712     // offline-apps.allow_by_default is now effective at the cache selection
   713     // algorithm code (nsContentSink).
   715     return NS_OK;
   716 }
   718 NS_IMETHODIMP
   719 nsOfflineCacheUpdateService::OfflineAppAllowed(nsIPrincipal *aPrincipal,
   720                                                nsIPrefBranch *aPrefBranch,
   721                                                bool *aAllowed)
   722 {
   723     return OfflineAppPermForPrincipal(aPrincipal, aPrefBranch, false, aAllowed);
   724 }
   726 NS_IMETHODIMP
   727 nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI *aURI,
   728                                                      nsIPrefBranch *aPrefBranch,
   729                                                      bool *aAllowed)
   730 {
   731     nsCOMPtr<nsIPrincipal> principal;
   732     nsContentUtils::GetSecurityManager()->
   733         GetNoAppCodebasePrincipal(aURI, getter_AddRefs(principal));
   734     return OfflineAppPermForPrincipal(principal, aPrefBranch, false, aAllowed);
   735 }
   737 nsresult
   738 nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI,
   739                                                     nsIPrefBranch *aPrefBranch,
   740                                                     bool *aPinned)
   741 {
   742     nsCOMPtr<nsIPrincipal> principal;
   743     nsContentUtils::GetSecurityManager()->
   744         GetNoAppCodebasePrincipal(aDocumentURI, getter_AddRefs(principal));
   745     return OfflineAppPermForPrincipal(principal, aPrefBranch, true, aPinned);
   746 }
   748 NS_IMETHODIMP
   749 nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow,
   750                                              nsIPrincipal *aPrincipal)
   751 {
   752     nsresult rv;
   754     if (GeckoProcessType_Default != XRE_GetProcessType()) {
   755         TabChild* child = TabChild::GetFrom(aWindow);
   756         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
   758         if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) {
   759             return NS_ERROR_FAILURE;
   760         }
   762         nsAutoCString domain;
   763         rv = aPrincipal->GetBaseDomain(domain);
   764         NS_ENSURE_SUCCESS(rv, rv);
   766         nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain);
   767     }
   768     else {
   769         nsCOMPtr<nsIPermissionManager> permissionManager =
   770             do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   771         if (!permissionManager)
   772             return NS_ERROR_NOT_AVAILABLE;
   774         rv = permissionManager->AddFromPrincipal(
   775             aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION,
   776             nsIPermissionManager::EXPIRE_NEVER, 0);
   777         NS_ENSURE_SUCCESS(rv, rv);
   778     }
   780     return NS_OK;
   781 }

mercurial