forked from mirrors/gecko-dev
		
	 b51e0fd0cc
			
		
	
	
		b51e0fd0cc
		
	
	
	
	
		
			
			> dom/media/gmp/CDMStorageIdProvider.cpp(63,10):  warning:
> local variable 'storageId' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/DisplayItemClip.cpp(581,10):  warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/DisplayItemClipChain.cpp(88,10):  warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/nsDisplayList.cpp(179,10):  warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> gfx/thebes/gfxWindowsPlatform.cpp(454,10):  warning:
> moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
Will remove std::move().
> gfx/thebes/gfxFontEntry.cpp(245,20):  warning:
> local variable 'name' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> netwerk/cookie/nsCookieService.cpp(4460,10):  warning:
> local variable 'path' will be copied despite being returned by name [-Wreturn-std-move]
GetPathFromURI() result is stored in an nsAutoCString, so it might as well return that type.
> toolkit/components/extensions/WebExtensionPolicy.cpp(462,12):  warning:
> local variable 'result' will be copied despite being returned by name [-Wreturn-std-move]
> toolkit/components/extensions/WebExtensionPolicy.cpp(475,10):  warning:
> local variable 'result' will be copied despite being returned by name [-Wreturn-std-move]
`result` may be empty or may be arbitrarily long, so I'll use nsCString inside the function.
> toolkit/xre/CmdLineAndEnvUtils.h(349,10):  warning:
> moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
Returning an UniquePtr, will remove std::move().
Also will `return s` instead of `return nullptr` when `(!s)`, to avoid extra construction which could also prevent elision (not entirely sure, but it's at least not worse!); and it's clearer that the two `return`s return the same already-constructed on-stack object.
> tools/profiler/core/shared-libraries-win32.cc(111,10):  warning:
> local variable 'version' will be copied despite being returned by name [-Wreturn-std-move]
nsPrintfCString -> nsCString, will add std::move().
> xpcom/glue/FileUtils.cpp(179,10):  warning:
> local variable 'fullName' will be copied despite being returned by name [-Wreturn-std-move]
> xpcom/glue/FileUtils.cpp(209,10):  warning:
> local variable 'path' will be copied despite being returned by name [-Wreturn-std-move]
nsAuto{,C}String -> ns{,C}String, will add std::move().
This allowed removals of 'AllowCompilerWarnings' from layout/painting,
netwerk/cookie, and toolkit/components/extensions.
Differential Revision: https://phabricator.services.mozilla.com/D5425
--HG--
extra : moz-landing-system : lando
		
	
			
		
			
				
	
	
		
			906 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			906 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 | |
|  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/ExtensionPolicyService.h"
 | |
| #include "mozilla/extensions/DocumentObserver.h"
 | |
| #include "mozilla/extensions/WebExtensionContentScript.h"
 | |
| #include "mozilla/extensions/WebExtensionPolicy.h"
 | |
| 
 | |
| #include "mozilla/AddonManagerWebAPI.h"
 | |
| #include "mozilla/ResultExtensions.h"
 | |
| #include "nsEscape.h"
 | |
| #include "nsIDocShell.h"
 | |
| #include "nsIObserver.h"
 | |
| #include "nsISubstitutingProtocolHandler.h"
 | |
| #include "nsNetUtil.h"
 | |
| #include "nsPrintfCString.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace extensions {
 | |
| 
 | |
| using namespace dom;
 | |
| 
 | |
| static const char kProto[] = "moz-extension";
 | |
| 
 | |
| static const char kBackgroundPageHTMLStart[] = "<!DOCTYPE html>\n\
 | |
| <html>\n\
 | |
|   <head><meta charset=\"utf-8\"></head>\n\
 | |
|   <body>";
 | |
| 
 | |
| static const char kBackgroundPageHTMLScript[] = "\n\
 | |
|     <script type=\"text/javascript\" src=\"%s\"></script>";
 | |
| 
 | |
| static const char kBackgroundPageHTMLEnd[] = "\n\
 | |
|   </body>\n\
 | |
| </html>";
 | |
| 
 | |
| static const char kRestrictedDomainPref[] =
 | |
|   "extensions.webextensions.restrictedDomains";
 | |
| 
 | |
| static inline ExtensionPolicyService&
 | |
| EPS()
 | |
| {
 | |
|   return ExtensionPolicyService::GetSingleton();
 | |
| }
 | |
| 
 | |
| static nsISubstitutingProtocolHandler*
 | |
| Proto()
 | |
| {
 | |
|   static nsCOMPtr<nsISubstitutingProtocolHandler> sHandler;
 | |
| 
 | |
|   if (MOZ_UNLIKELY(!sHandler)) {
 | |
|     nsCOMPtr<nsIIOService> ios = do_GetIOService();
 | |
|     MOZ_RELEASE_ASSERT(ios);
 | |
| 
 | |
|     nsCOMPtr<nsIProtocolHandler> handler;
 | |
|     ios->GetProtocolHandler(kProto, getter_AddRefs(handler));
 | |
| 
 | |
|     sHandler = do_QueryInterface(handler);
 | |
|     MOZ_RELEASE_ASSERT(sHandler);
 | |
| 
 | |
|     ClearOnShutdown(&sHandler);
 | |
|   }
 | |
| 
 | |
|   return sHandler;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool
 | |
| ParseGlobs(GlobalObject& aGlobal, Sequence<OwningMatchGlobOrString> aGlobs,
 | |
|            nsTArray<RefPtr<MatchGlob>>& aResult, ErrorResult& aRv)
 | |
| {
 | |
|   for (auto& elem : aGlobs) {
 | |
|     if (elem.IsMatchGlob()) {
 | |
|       aResult.AppendElement(elem.GetAsMatchGlob());
 | |
|     } else {
 | |
|       RefPtr<MatchGlob> glob = MatchGlob::Constructor(aGlobal,
 | |
|                                                       elem.GetAsString(),
 | |
|                                                       true, aRv);
 | |
|       if (aRv.Failed()) {
 | |
|         return false;
 | |
|       }
 | |
|       aResult.AppendElement(glob);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| enum class ErrorBehavior {
 | |
|   CreateEmptyPattern,
 | |
|   Fail,
 | |
| };
 | |
| 
 | |
| already_AddRefed<MatchPatternSet>
 | |
| ParseMatches(GlobalObject& aGlobal,
 | |
|              const OwningMatchPatternSetOrStringSequence& aMatches,
 | |
|              const MatchPatternOptions& aOptions,
 | |
|              ErrorBehavior aErrorBehavior,
 | |
|              ErrorResult& aRv)
 | |
| {
 | |
|   if (aMatches.IsMatchPatternSet()) {
 | |
|     return do_AddRef(aMatches.GetAsMatchPatternSet().get());
 | |
|   }
 | |
| 
 | |
|   const auto& strings = aMatches.GetAsStringSequence();
 | |
| 
 | |
|   nsTArray<OwningStringOrMatchPattern> patterns;
 | |
|   if (!patterns.SetCapacity(strings.Length(), fallible)) {
 | |
|     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   for (auto& string : strings) {
 | |
|     OwningStringOrMatchPattern elt;
 | |
|     elt.SetAsString() = string;
 | |
|     patterns.AppendElement(elt);
 | |
|   }
 | |
| 
 | |
|   RefPtr<MatchPatternSet> result = MatchPatternSet::Constructor(
 | |
|     aGlobal, patterns, aOptions, aRv);
 | |
| 
 | |
|   if (aRv.Failed() && aErrorBehavior == ErrorBehavior::CreateEmptyPattern) {
 | |
|     aRv.SuppressException();
 | |
|     result = MatchPatternSet::Constructor(aGlobal, {}, aOptions, aRv);
 | |
|   }
 | |
| 
 | |
|   return result.forget();
 | |
| }
 | |
| 
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * WebExtensionPolicy
 | |
|  *****************************************************************************/
 | |
| 
 | |
| WebExtensionPolicy::WebExtensionPolicy(GlobalObject& aGlobal,
 | |
|                                        const WebExtensionInit& aInit,
 | |
|                                        ErrorResult& aRv)
 | |
|   : mId(NS_AtomizeMainThread(aInit.mId))
 | |
|   , mHostname(aInit.mMozExtensionHostname)
 | |
|   , mName(aInit.mName)
 | |
|   , mContentSecurityPolicy(aInit.mContentSecurityPolicy)
 | |
|   , mLocalizeCallback(aInit.mLocalizeCallback)
 | |
|   , mPermissions(new AtomSet(aInit.mPermissions))
 | |
| {
 | |
|   if (!ParseGlobs(aGlobal, aInit.mWebAccessibleResources, mWebAccessiblePaths,
 | |
|                   aRv)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MatchPatternOptions options;
 | |
|   options.mRestrictSchemes = !HasPermission(nsGkAtoms::mozillaAddons);
 | |
| 
 | |
|   mHostPermissions = ParseMatches(aGlobal, aInit.mAllowedOrigins, options,
 | |
|                                   ErrorBehavior::CreateEmptyPattern, aRv);
 | |
|   if (aRv.Failed()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!aInit.mBackgroundScripts.IsNull()) {
 | |
|     mBackgroundScripts.SetValue().AppendElements(aInit.mBackgroundScripts.Value());
 | |
|   }
 | |
| 
 | |
|   if (mContentSecurityPolicy.IsVoid()) {
 | |
|     EPS().DefaultCSP(mContentSecurityPolicy);
 | |
|   }
 | |
| 
 | |
|   mContentScripts.SetCapacity(aInit.mContentScripts.Length());
 | |
|   for (const auto& scriptInit : aInit.mContentScripts) {
 | |
|     // The activeTab permission is only for dynamically injected scripts,
 | |
|     // it cannot be used for declarative content scripts.
 | |
|     if (scriptInit.mHasActiveTabPermission) {
 | |
|       aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     RefPtr<WebExtensionContentScript> contentScript =
 | |
|       new WebExtensionContentScript(aGlobal, *this, scriptInit, aRv);
 | |
|     if (aRv.Failed()) {
 | |
|       return;
 | |
|     }
 | |
|     mContentScripts.AppendElement(std::move(contentScript));
 | |
|   }
 | |
| 
 | |
|   nsresult rv = NS_NewURI(getter_AddRefs(mBaseURI), aInit.mBaseURL);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     aRv.Throw(rv);
 | |
|   }
 | |
| }
 | |
| 
 | |
| already_AddRefed<WebExtensionPolicy>
 | |
| WebExtensionPolicy::Constructor(GlobalObject& aGlobal,
 | |
|                                 const WebExtensionInit& aInit,
 | |
|                                 ErrorResult& aRv)
 | |
| {
 | |
|   RefPtr<WebExtensionPolicy> policy = new WebExtensionPolicy(aGlobal, aInit, aRv);
 | |
|   if (aRv.Failed()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return policy.forget();
 | |
| }
 | |
| 
 | |
| 
 | |
| /* static */ void
 | |
| WebExtensionPolicy::GetActiveExtensions(dom::GlobalObject& aGlobal,
 | |
|                                         nsTArray<RefPtr<WebExtensionPolicy>>& aResults)
 | |
| {
 | |
|   EPS().GetAll(aResults);
 | |
| }
 | |
| 
 | |
| /* static */ already_AddRefed<WebExtensionPolicy>
 | |
| WebExtensionPolicy::GetByID(dom::GlobalObject& aGlobal, const nsAString& aID)
 | |
| {
 | |
|   return do_AddRef(EPS().GetByID(aID));
 | |
| }
 | |
| 
 | |
| /* static */ already_AddRefed<WebExtensionPolicy>
 | |
| WebExtensionPolicy::GetByHostname(dom::GlobalObject& aGlobal, const nsACString& aHostname)
 | |
| {
 | |
|   return do_AddRef(EPS().GetByHost(aHostname));
 | |
| }
 | |
| 
 | |
| /* static */ already_AddRefed<WebExtensionPolicy>
 | |
| WebExtensionPolicy::GetByURI(dom::GlobalObject& aGlobal, nsIURI* aURI)
 | |
| {
 | |
|   return do_AddRef(EPS().GetByURL(aURI));
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::SetActive(bool aActive, ErrorResult& aRv)
 | |
| {
 | |
|   if (aActive == mActive) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   bool ok = aActive ? Enable() : Disable();
 | |
| 
 | |
|   if (!ok) {
 | |
|     aRv.Throw(NS_ERROR_UNEXPECTED);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool
 | |
| WebExtensionPolicy::Enable()
 | |
| {
 | |
|   MOZ_ASSERT(!mActive);
 | |
| 
 | |
|   if (!EPS().RegisterExtension(*this)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   Unused << Proto()->SetSubstitution(MozExtensionHostname(), mBaseURI);
 | |
| 
 | |
|   mActive = true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| WebExtensionPolicy::Disable()
 | |
| {
 | |
|   MOZ_ASSERT(mActive);
 | |
|   MOZ_ASSERT(EPS().GetByID(Id()) == this);
 | |
| 
 | |
|   if (!EPS().UnregisterExtension(*this)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   Unused << Proto()->SetSubstitution(MozExtensionHostname(), nullptr);
 | |
| 
 | |
|   mActive = false;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::GetURL(const nsAString& aPath,
 | |
|                            nsAString& aResult,
 | |
|                            ErrorResult& aRv) const
 | |
| {
 | |
|   auto result = GetURL(aPath);
 | |
|   if (result.isOk()) {
 | |
|     aResult = result.unwrap();
 | |
|   } else {
 | |
|     aRv.Throw(result.unwrapErr());
 | |
|   }
 | |
| }
 | |
| 
 | |
| Result<nsString, nsresult>
 | |
| WebExtensionPolicy::GetURL(const nsAString& aPath) const
 | |
| {
 | |
|   nsPrintfCString spec("%s://%s/", kProto, mHostname.get());
 | |
| 
 | |
|   nsCOMPtr<nsIURI> uri;
 | |
|   MOZ_TRY(NS_NewURI(getter_AddRefs(uri), spec));
 | |
| 
 | |
|   MOZ_TRY(uri->Resolve(NS_ConvertUTF16toUTF8(aPath), spec));
 | |
| 
 | |
|   return NS_ConvertUTF8toUTF16(spec);
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::RegisterContentScript(WebExtensionContentScript& script,
 | |
|                                           ErrorResult& aRv)
 | |
| {
 | |
|   // Raise an "invalid argument" error if the script is not related to
 | |
|   // the expected extension or if it is already registered.
 | |
|   if (script.mExtension != this || mContentScripts.Contains(&script)) {
 | |
|     aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebExtensionContentScript> newScript = &script;
 | |
| 
 | |
|   if (!mContentScripts.AppendElement(std::move(newScript), fallible)) {
 | |
|     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   WebExtensionPolicy_Binding::ClearCachedContentScriptsValue(this);
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::UnregisterContentScript(const WebExtensionContentScript& script,
 | |
|                                             ErrorResult& aRv)
 | |
| {
 | |
|   if (script.mExtension != this || !mContentScripts.RemoveElement(&script)) {
 | |
|     aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   WebExtensionPolicy_Binding::ClearCachedContentScriptsValue(this);
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::InjectContentScripts(ErrorResult& aRv)
 | |
| {
 | |
|   nsresult rv = EPS().InjectContentScripts(this);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     aRv.Throw(rv);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */ bool
 | |
| WebExtensionPolicy::UseRemoteWebExtensions(GlobalObject& aGlobal)
 | |
| {
 | |
|   return EPS().UseRemoteExtensions();
 | |
| }
 | |
| 
 | |
| /* static */ bool
 | |
| WebExtensionPolicy::IsExtensionProcess(GlobalObject& aGlobal)
 | |
| {
 | |
|   return EPS().IsExtensionProcess();
 | |
| }
 | |
| 
 | |
| namespace {
 | |
|   /**
 | |
|    * Maintains a dynamically updated AtomSet based on the comma-separated
 | |
|    * values in the given string pref.
 | |
|    */
 | |
|   class AtomSetPref : public nsIObserver
 | |
|                     , public nsSupportsWeakReference
 | |
|   {
 | |
|   public:
 | |
|     NS_DECL_ISUPPORTS
 | |
|     NS_DECL_NSIOBSERVER
 | |
| 
 | |
|     static already_AddRefed<AtomSetPref>
 | |
|     Create(const nsCString& aPref)
 | |
|     {
 | |
|       RefPtr<AtomSetPref> self = new AtomSetPref(aPref.get());
 | |
|       Preferences::AddWeakObserver(self, aPref);
 | |
|       return self.forget();
 | |
|     }
 | |
| 
 | |
|     const AtomSet& Get() const;
 | |
| 
 | |
|     bool Contains(const nsAtom* aAtom) const
 | |
|     {
 | |
|       return Get().Contains(aAtom);
 | |
|     }
 | |
| 
 | |
|   protected:
 | |
|     virtual ~AtomSetPref() = default;
 | |
| 
 | |
|     explicit AtomSetPref(const char* aPref) : mPref(aPref)
 | |
|     {}
 | |
| 
 | |
|   private:
 | |
|     mutable RefPtr<AtomSet> mAtomSet;
 | |
|     const char* mPref;
 | |
|   };
 | |
| 
 | |
|   const AtomSet&
 | |
|   AtomSetPref::Get() const
 | |
|   {
 | |
|     if (!mAtomSet) {
 | |
|       nsAutoCString eltsString;
 | |
|       Unused << Preferences::GetCString(mPref, eltsString);
 | |
| 
 | |
|       AutoTArray<nsString, 32> elts;
 | |
|       for (const nsACString& elt : eltsString.Split(',')) {
 | |
|         elts.AppendElement(NS_ConvertUTF8toUTF16(elt));
 | |
|         elts.LastElement().StripWhitespace();
 | |
|       }
 | |
|       mAtomSet = new AtomSet(elts);
 | |
|     }
 | |
| 
 | |
|     return *mAtomSet;
 | |
|   }
 | |
| 
 | |
|   NS_IMETHODIMP
 | |
|   AtomSetPref::Observe(nsISupports *aSubject, const char *aTopic,
 | |
|                        const char16_t *aData)
 | |
|   {
 | |
|     mAtomSet = nullptr;
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   NS_IMPL_ISUPPORTS(AtomSetPref, nsIObserver, nsISupportsWeakReference)
 | |
| };
 | |
| 
 | |
| /* static */ bool
 | |
| WebExtensionPolicy::IsRestrictedDoc(const DocInfo& aDoc)
 | |
| {
 | |
|   // With the exception of top-level about:blank documents with null
 | |
|   // principals, we never match documents that have non-codebase principals,
 | |
|   // including those with null principals or system principals.
 | |
|   if (aDoc.Principal() && !aDoc.Principal()->GetIsCodebasePrincipal()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return IsRestrictedURI(aDoc.PrincipalURL());
 | |
| }
 | |
| 
 | |
| /* static */ bool
 | |
| WebExtensionPolicy::IsRestrictedURI(const URLInfo &aURI)
 | |
| {
 | |
|   static RefPtr<AtomSetPref> domains;
 | |
|   if (!domains) {
 | |
|     domains = AtomSetPref::Create(nsLiteralCString(kRestrictedDomainPref));
 | |
|     ClearOnShutdown(&domains);
 | |
|   }
 | |
| 
 | |
|   if (domains->Contains(aURI.HostAtom())) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   if (AddonManagerWebAPI::IsValidSite(aURI.URI())) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| nsCString
 | |
| WebExtensionPolicy::BackgroundPageHTML() const
 | |
| {
 | |
|   nsCString result;
 | |
| 
 | |
|   if (mBackgroundScripts.IsNull()) {
 | |
|     result.SetIsVoid(true);
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   result.AppendLiteral(kBackgroundPageHTMLStart);
 | |
| 
 | |
|   for (auto& script : mBackgroundScripts.Value()) {
 | |
|     nsCString escaped;
 | |
|     nsAppendEscapedHTML(NS_ConvertUTF16toUTF8(script), escaped);
 | |
| 
 | |
|     result.AppendPrintf(kBackgroundPageHTMLScript, escaped.get());
 | |
|   }
 | |
| 
 | |
|   result.AppendLiteral(kBackgroundPageHTMLEnd);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::Localize(const nsAString& aInput, nsString& aOutput) const
 | |
| {
 | |
|   mLocalizeCallback->Call(aInput, aOutput);
 | |
| }
 | |
| 
 | |
| 
 | |
| JSObject*
 | |
| WebExtensionPolicy::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
 | |
| {
 | |
|   return WebExtensionPolicy_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| void
 | |
| WebExtensionPolicy::GetContentScripts(nsTArray<RefPtr<WebExtensionContentScript>>& aScripts) const
 | |
| {
 | |
|   aScripts.AppendElements(mContentScripts);
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionPolicy, mParent,
 | |
|                                       mLocalizeCallback,
 | |
|                                       mHostPermissions,
 | |
|                                       mWebAccessiblePaths,
 | |
|                                       mContentScripts)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebExtensionPolicy)
 | |
|   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(WebExtensionPolicy)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(WebExtensionPolicy)
 | |
| 
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * WebExtensionContentScript / MozDocumentMatcher
 | |
|  *****************************************************************************/
 | |
| 
 | |
| /* static */ already_AddRefed<MozDocumentMatcher>
 | |
| MozDocumentMatcher::Constructor(GlobalObject& aGlobal,
 | |
|                                 const dom::MozDocumentMatcherInit& aInit,
 | |
|                                 ErrorResult& aRv)
 | |
| {
 | |
|   RefPtr<MozDocumentMatcher> matcher = new MozDocumentMatcher(aGlobal, aInit,
 | |
|                                                               false, aRv);
 | |
|   if (aRv.Failed()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return matcher.forget();
 | |
| }
 | |
| 
 | |
| /* static */ already_AddRefed<WebExtensionContentScript>
 | |
| WebExtensionContentScript::Constructor(GlobalObject& aGlobal,
 | |
|                                        WebExtensionPolicy& aExtension,
 | |
|                                        const ContentScriptInit& aInit,
 | |
|                                        ErrorResult& aRv)
 | |
| {
 | |
|   RefPtr<WebExtensionContentScript> script = new WebExtensionContentScript(
 | |
|       aGlobal, aExtension, aInit, aRv);
 | |
|   if (aRv.Failed()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return script.forget();
 | |
| }
 | |
| 
 | |
| MozDocumentMatcher::MozDocumentMatcher(GlobalObject& aGlobal,
 | |
|                                        const dom::MozDocumentMatcherInit& aInit,
 | |
|                                        bool aRestricted,
 | |
|                                        ErrorResult& aRv)
 | |
|   : mHasActiveTabPermission(aInit.mHasActiveTabPermission)
 | |
|   , mRestricted(aRestricted)
 | |
|   , mAllFrames(aInit.mAllFrames)
 | |
|   , mFrameID(aInit.mFrameID)
 | |
|   , mMatchAboutBlank(aInit.mMatchAboutBlank)
 | |
| {
 | |
|   MatchPatternOptions options;
 | |
|   options.mRestrictSchemes = mRestricted;
 | |
| 
 | |
|   mMatches = ParseMatches(aGlobal, aInit.mMatches, options,
 | |
|                           ErrorBehavior::CreateEmptyPattern, aRv);
 | |
|   if (aRv.Failed()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!aInit.mExcludeMatches.IsNull()) {
 | |
|     mExcludeMatches = ParseMatches(aGlobal, aInit.mExcludeMatches.Value(),
 | |
|                                    options, ErrorBehavior::CreateEmptyPattern,
 | |
|                                    aRv);
 | |
|     if (aRv.Failed()) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!aInit.mIncludeGlobs.IsNull()) {
 | |
|     if (!ParseGlobs(aGlobal, aInit.mIncludeGlobs.Value(), mIncludeGlobs.SetValue(),
 | |
|                     aRv)) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!aInit.mExcludeGlobs.IsNull()) {
 | |
|     if (!ParseGlobs(aGlobal, aInit.mExcludeGlobs.Value(), mExcludeGlobs.SetValue(),
 | |
|                     aRv)) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| WebExtensionContentScript::WebExtensionContentScript(GlobalObject& aGlobal,
 | |
|                                                      WebExtensionPolicy& aExtension,
 | |
|                                                      const ContentScriptInit& aInit,
 | |
|                                                      ErrorResult& aRv)
 | |
|   : MozDocumentMatcher(aGlobal, aInit, !aExtension.HasPermission(nsGkAtoms::mozillaAddons), aRv)
 | |
|   , mCssPaths(aInit.mCssPaths)
 | |
|   , mJsPaths(aInit.mJsPaths)
 | |
|   , mRunAt(aInit.mRunAt)
 | |
| {
 | |
|   mExtension = &aExtension;
 | |
| }
 | |
| 
 | |
| bool
 | |
| MozDocumentMatcher::Matches(const DocInfo& aDoc) const
 | |
| {
 | |
|   if (!mFrameID.IsNull()) {
 | |
|     if (aDoc.FrameID() != mFrameID.Value()) {
 | |
|       return false;
 | |
|     }
 | |
|   } else {
 | |
|     if (!mAllFrames && !aDoc.IsTopLevel()) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!mMatchAboutBlank && aDoc.URL().InheritsPrincipal()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Top-level about:blank is a special case. We treat it as a match if
 | |
|   // matchAboutBlank is true and it has the null principal. In all other
 | |
|   // cases, we test the URL of the principal that it inherits.
 | |
|   if (mMatchAboutBlank && aDoc.IsTopLevel() &&
 | |
|       aDoc.URL().Spec().EqualsLiteral("about:blank") &&
 | |
|       aDoc.Principal() && aDoc.Principal()->GetIsNullPrincipal()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   if (mRestricted && mExtension->IsRestrictedDoc(aDoc)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   auto& urlinfo = aDoc.PrincipalURL();
 | |
|   if (mHasActiveTabPermission && aDoc.ShouldMatchActiveTabPermission() &&
 | |
|       MatchPattern::MatchesAllURLs(urlinfo)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return MatchesURI(urlinfo);
 | |
| }
 | |
| 
 | |
| bool
 | |
| MozDocumentMatcher::MatchesURI(const URLInfo& aURL) const
 | |
| {
 | |
|   if (!mMatches->Matches(aURL)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (mExcludeMatches && mExcludeMatches->Matches(aURL)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!mIncludeGlobs.IsNull() && !mIncludeGlobs.Value().Matches(aURL.Spec())) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!mExcludeGlobs.IsNull() && mExcludeGlobs.Value().Matches(aURL.Spec())) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (mRestricted && mExtension->IsRestrictedURI(aURL)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| JSObject*
 | |
| MozDocumentMatcher::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
 | |
| {
 | |
|   return MozDocumentMatcher_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| JSObject*
 | |
| WebExtensionContentScript::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
 | |
| {
 | |
|   return WebExtensionContentScript_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MozDocumentMatcher,
 | |
|                                       mMatches, mExcludeMatches,
 | |
|                                       mIncludeGlobs, mExcludeGlobs,
 | |
|                                       mExtension)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozDocumentMatcher)
 | |
|   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(MozDocumentMatcher)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(MozDocumentMatcher)
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * MozDocumentObserver
 | |
|  *****************************************************************************/
 | |
| 
 | |
| /* static */ already_AddRefed<DocumentObserver>
 | |
| DocumentObserver::Constructor(GlobalObject& aGlobal,
 | |
|                               dom::MozDocumentCallback& aCallbacks,
 | |
|                               ErrorResult& aRv)
 | |
| {
 | |
|   RefPtr<DocumentObserver> matcher = new DocumentObserver(aGlobal.GetAsSupports(), aCallbacks);
 | |
|   return matcher.forget();
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| DocumentObserver::Observe(const dom::Sequence<OwningNonNull<MozDocumentMatcher>>& matchers, ErrorResult& aRv)
 | |
| {
 | |
|   if (!EPS().RegisterObserver(*this)) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return;
 | |
|   }
 | |
|   mMatchers.Clear();
 | |
|   for (auto& matcher : matchers) {
 | |
|     if (!mMatchers.AppendElement(matcher, fallible)) {
 | |
|       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| DocumentObserver::Disconnect()
 | |
| {
 | |
|   Unused << EPS().UnregisterObserver(*this);
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher, nsPIDOMWindowOuter* aWindow)
 | |
| {
 | |
|   IgnoredErrorResult rv;
 | |
|   mCallbacks->OnNewDocument(aMatcher, aWindow, rv);
 | |
| }
 | |
| 
 | |
| void
 | |
| DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher, nsILoadInfo* aLoadInfo)
 | |
| {
 | |
|   IgnoredErrorResult rv;
 | |
|   mCallbacks->OnPreloadDocument(aMatcher, aLoadInfo, rv);
 | |
| }
 | |
| 
 | |
| 
 | |
| JSObject*
 | |
| DocumentObserver::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
 | |
| {
 | |
|   return MozDocumentObserver_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DocumentObserver, mCallbacks, mMatchers, mParent)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DocumentObserver)
 | |
|   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(DocumentObserver)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(DocumentObserver)
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * DocInfo
 | |
|  *****************************************************************************/
 | |
| 
 | |
| DocInfo::DocInfo(const URLInfo& aURL, nsILoadInfo* aLoadInfo)
 | |
|   : mURL(aURL)
 | |
|   , mObj(AsVariant(aLoadInfo))
 | |
| {}
 | |
| 
 | |
| DocInfo::DocInfo(nsPIDOMWindowOuter* aWindow)
 | |
|   : mURL(aWindow->GetDocumentURI())
 | |
|   , mObj(AsVariant(aWindow))
 | |
| {}
 | |
| 
 | |
| bool
 | |
| DocInfo::IsTopLevel() const
 | |
| {
 | |
|   if (mIsTopLevel.isNothing()) {
 | |
|     struct Matcher
 | |
|     {
 | |
|       bool match(Window aWin) { return aWin->IsTopLevelWindow(); }
 | |
|       bool match(LoadInfo aLoadInfo) { return aLoadInfo->GetIsTopLevelLoad(); }
 | |
|     };
 | |
|     mIsTopLevel.emplace(mObj.match(Matcher()));
 | |
|   }
 | |
|   return mIsTopLevel.ref();
 | |
| }
 | |
| 
 | |
| bool
 | |
| WindowShouldMatchActiveTab(nsPIDOMWindowOuter* aWin)
 | |
| {
 | |
|   if (aWin->IsTopLevelWindow()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   nsIDocShell* docshell = aWin->GetDocShell();
 | |
|   if (!docshell || docshell->GetCreatedDynamically()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsIDocument* doc = aWin->GetExtantDoc();
 | |
|   if (!doc) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsIChannel* channel = doc->GetChannel();
 | |
|   if (!channel) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
 | |
| 
 | |
|   if (!loadInfo) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!loadInfo->GetOriginalFrameSrcLoad()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> parent = aWin->GetParent();
 | |
|   MOZ_ASSERT(parent != nullptr);
 | |
|   return WindowShouldMatchActiveTab(parent);
 | |
| }
 | |
| 
 | |
| bool
 | |
| DocInfo::ShouldMatchActiveTabPermission() const
 | |
| {
 | |
|   struct Matcher
 | |
|   {
 | |
|     bool match(Window aWin) { return WindowShouldMatchActiveTab(aWin); }
 | |
|     bool match(LoadInfo aLoadInfo) { return false; }
 | |
|   };
 | |
|   return mObj.match(Matcher());
 | |
| }
 | |
| 
 | |
| uint64_t
 | |
| DocInfo::FrameID() const
 | |
| {
 | |
|   if (mFrameID.isNothing()) {
 | |
|     if (IsTopLevel()) {
 | |
|       mFrameID.emplace(0);
 | |
|     } else {
 | |
|       struct Matcher
 | |
|       {
 | |
|         uint64_t match(Window aWin) { return aWin->WindowID(); }
 | |
|         uint64_t match(LoadInfo aLoadInfo) { return aLoadInfo->GetOuterWindowID(); }
 | |
|       };
 | |
|       mFrameID.emplace(mObj.match(Matcher()));
 | |
|     }
 | |
|   }
 | |
|   return mFrameID.ref();
 | |
| }
 | |
| 
 | |
| nsIPrincipal*
 | |
| DocInfo::Principal() const
 | |
| {
 | |
|   if (mPrincipal.isNothing()) {
 | |
|     struct Matcher
 | |
|     {
 | |
|       explicit Matcher(const DocInfo& aThis) : mThis(aThis) {}
 | |
|       const DocInfo& mThis;
 | |
| 
 | |
|       nsIPrincipal* match(Window aWin)
 | |
|       {
 | |
|         nsCOMPtr<nsIDocument> doc = aWin->GetDoc();
 | |
|         return doc->NodePrincipal();
 | |
|       }
 | |
|       nsIPrincipal* match(LoadInfo aLoadInfo)
 | |
|       {
 | |
|         if (!(mThis.URL().InheritsPrincipal() || aLoadInfo->GetForceInheritPrincipal())) {
 | |
|           return nullptr;
 | |
|         }
 | |
|         if (auto principal = aLoadInfo->PrincipalToInherit()) {
 | |
|           return principal;
 | |
|         }
 | |
|         return aLoadInfo->TriggeringPrincipal();
 | |
|       }
 | |
|     };
 | |
|     mPrincipal.emplace(mObj.match(Matcher(*this)));
 | |
|   }
 | |
|   return mPrincipal.ref();
 | |
| }
 | |
| 
 | |
| const URLInfo&
 | |
| DocInfo::PrincipalURL() const
 | |
| {
 | |
|   if (!(Principal() && Principal()->GetIsCodebasePrincipal())) {
 | |
|     return URL();
 | |
|   }
 | |
| 
 | |
|   if (mPrincipalURL.isNothing()) {
 | |
|     nsIPrincipal* prin = Principal();
 | |
|     nsCOMPtr<nsIURI> uri;
 | |
|     if (NS_SUCCEEDED(prin->GetURI(getter_AddRefs(uri)))) {
 | |
|       MOZ_DIAGNOSTIC_ASSERT(uri);
 | |
|       mPrincipalURL.emplace(uri);
 | |
|     } else {
 | |
|       mPrincipalURL.emplace(URL());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return mPrincipalURL.ref();
 | |
| }
 | |
| 
 | |
| } // namespace extensions
 | |
| } // namespace mozilla
 |