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.

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

mercurial