From 4fc7ebc647902fa0cd79b76289e1428a65bb1fd9 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 19 Nov 2013 23:15:59 +0100 Subject: [PATCH] Bug 918880 - MaybeAllowOfflineAppByDefault must work on child processes, r=jduell --- b2g/chrome/content/shell.js | 3 + content/base/public/nsContentUtils.h | 2 +- content/base/src/nsContentSink.cpp | 2 +- content/base/src/nsContentUtils.cpp | 20 +++--- dom/ipc/PBrowser.ipdl | 7 +++ dom/ipc/TabParent.cpp | 8 +++ dom/ipc/TabParent.h | 1 + uriloader/prefetch/nsIOfflineCacheUpdate.idl | 9 ++- uriloader/prefetch/nsOfflineCacheUpdate.h | 5 ++ .../prefetch/nsOfflineCacheUpdateService.cpp | 62 +++++++++++++++++++ 10 files changed, 104 insertions(+), 15 deletions(-) diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index be0456240e5..7f0d712df84 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -511,6 +511,9 @@ var shell = { Services.perms.addFromPrincipal(principal, 'offline-app', Ci.nsIPermissionManager.ALLOW_ACTION); + let documentURI = Services.io.newURI(contentWindow.document.documentURI, + null, + null); let manifestURI = Services.io.newURI(manifest, null, documentURI); let updateService = Cc['@mozilla.org/offlinecacheupdate-service;1'] .getService(Ci.nsIOfflineCacheUpdateService); diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index a0a41ec34d3..04609ccd838 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1460,7 +1460,7 @@ public: * If offline-apps.allow_by_default is true, we set offline-app permission * for the principal and return true. Otherwise false. */ - static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal); + static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, nsIDOMWindow *aWindow); /** * Increases the count of blockers preventing scripts from running. diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index e55d10aad2b..993c480dbfe 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -1055,7 +1055,7 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec) // Only continue if the document has permission to use offline APIs or // when preferences indicate to permit it automatically. if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) && - !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal()) && + !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) && !nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) { return; } diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 2de32fb8b66..b01dc799da7 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -1428,7 +1428,8 @@ nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal) } bool -nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) +nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, + nsIDOMWindow *aWindow) { if (!Preferences::GetRootBranch()) return false; @@ -1444,19 +1445,14 @@ nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) if (!allowedByDefault) return false; - nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); - if (!permissionManager) + nsCOMPtr updateService = + do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); + if (!updateService) { return false; + } - rv = permissionManager->AddFromPrincipal( - aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, - nsIPermissionManager::EXPIRE_NEVER, 0); - if (NS_FAILED(rv)) - return false; - - // We have added the permission - return true; + rv = updateService->AllowOfflineApp(aWindow, aPrincipal); + return NS_SUCCEEDED(rv); } // static diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index a66e9f45297..ae92d47b85c 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -255,6 +255,13 @@ parent: POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI, bool stickDocument); + /** + * Sets "offline-app" permission for the principal. Called when we hit + * a web app with the manifest attribute in and + * offline-apps.allow_by_default is set to true. + */ + SetOfflinePermission(Principal principal); + sync PIndexedDB(nsCString group, nsCString asciiOrigin) returns (bool allowed); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 365450cb75d..7d13af46010 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1577,6 +1577,14 @@ TabParent::DeallocPOfflineCacheUpdateParent(mozilla::docshell::POfflineCacheUpda return true; } +bool +TabParent::RecvSetOfflinePermission(const IPC::Principal& aPrincipal) +{ + nsIPrincipal* principal = aPrincipal; + nsContentUtils::MaybeAllowOfflineAppByDefault(principal, nullptr); + return true; +} + bool TabParent::ShouldDelayDialogs() { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 5daae4dea50..4d645c33339 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -236,6 +236,7 @@ public: const URIParams& aDocumentURI, const bool& stickDocument) MOZ_OVERRIDE; virtual bool DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* actor); + virtual bool RecvSetOfflinePermission(const IPC::Principal& principal); bool GetGlobalJSObject(JSContext* cx, JSObject** globalp); diff --git a/uriloader/prefetch/nsIOfflineCacheUpdate.idl b/uriloader/prefetch/nsIOfflineCacheUpdate.idl index 50efaeb178f..51f41e4bb11 100644 --- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl +++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl @@ -192,7 +192,7 @@ interface nsIOfflineCacheUpdate : nsISupports { readonly attribute uint64_t byteProgress; }; -[scriptable, uuid(cf362a31-4166-4994-8443-b68704ecdcc0)] +[scriptable, uuid(6ee353ba-11ea-4008-a78a-55b343fb2a49)] interface nsIOfflineCacheUpdateService : nsISupports { /** * Constants for the offline-app permission. @@ -291,4 +291,11 @@ interface nsIOfflineCacheUpdateService : nsISupports { */ boolean offlineAppAllowedForURI(in nsIURI aURI, in nsIPrefBranch aPrefBranch); + + /** + * Sets the "offline-app" permission for the principal. + * In the single process model calls directly on permission manager. + * In the multi process model dispatches to the parent process. + */ + void allowOfflineApp(in nsIDOMWindow aWindow, in nsIPrincipal aPrincipal); }; diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.h b/uriloader/prefetch/nsOfflineCacheUpdate.h index b9cb4488603..63373e9bf2e 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdate.h +++ b/uriloader/prefetch/nsOfflineCacheUpdate.h @@ -31,6 +31,8 @@ #include "nsWeakReference.h" #include "nsICryptoHash.h" #include "mozilla/Attributes.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" class nsOfflineCacheUpdate; @@ -356,10 +358,13 @@ public: nsIPrefBranch *aPrefBranch, bool *aPinned); + static nsTHashtable* AllowedDomains(); + private: nsresult ProcessNextUpdate(); nsTArray > mUpdates; + static nsTHashtable* mAllowedDomains; bool mDisabled; bool mUpdateRunning; diff --git a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp index 1749a767902..73c7301b811 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp @@ -48,11 +48,28 @@ #include "mozilla/Preferences.h" #include "mozilla/Attributes.h" #include "nsIDiskSpaceWatcher.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeOwner.h" +#include "mozilla/dom/TabChild.h" +#include "mozilla/dom/PermissionMessageUtils.h" using namespace mozilla; +using namespace mozilla::dom; static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr; +nsTHashtable* nsOfflineCacheUpdateService::mAllowedDomains = nullptr; + +nsTHashtable* nsOfflineCacheUpdateService::AllowedDomains() +{ + if (!mAllowedDomains) + mAllowedDomains = new nsTHashtable(); + + return mAllowedDomains; +} + + typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent; typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild; typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue; @@ -681,6 +698,15 @@ OfflineAppPermForURI(nsIURI *aURI, } } + nsAutoCString domain; + rv = innerURI->GetAsciiHost(domain); + NS_ENSURE_SUCCESS(rv, rv); + + if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) { + *aAllowed = true; + return NS_OK; + } + nsCOMPtr permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); if (!permissionManager) { @@ -717,3 +743,39 @@ nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI, { return OfflineAppPermForURI(aDocumentURI, aPrefBranch, true, aPinned); } + +NS_IMETHODIMP +nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow, + nsIPrincipal *aPrincipal) +{ + nsresult rv; + + if (GeckoProcessType_Default != XRE_GetProcessType()) { + TabChild* child = TabChild::GetFrom(aWindow); + NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); + + if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) { + return NS_ERROR_FAILURE; + } + + nsAutoCString domain; + rv = aPrincipal->GetBaseDomain(domain); + NS_ENSURE_SUCCESS(rv, rv); + + nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain); + } + else { + nsCOMPtr permissionManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + if (!permissionManager) + return NS_ERROR_NOT_AVAILABLE; + + rv = permissionManager->AddFromPrincipal( + aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, + nsIPermissionManager::EXPIRE_NEVER, 0); + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +}