1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
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 file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "mozilla/ExtensionPolicyService.h"
7 #include "mozilla/extensions/WebExtensionContentScript.h"
8 #include "mozilla/extensions/WebExtensionPolicy.h"
9
10 #include "mozilla/AddonManagerWebAPI.h"
11 #include "mozilla/ResultExtensions.h"
12 #include "nsEscape.h"
13 #include "nsIDocShell.h"
14 #include "nsIObserver.h"
15 #include "nsISubstitutingProtocolHandler.h"
16 #include "nsNetUtil.h"
17 #include "nsPrintfCString.h"
18
19 namespace mozilla {
20 namespace extensions {
21
22 using namespace dom;
23
24 static const char kProto[] = "moz-extension";
25
26 static const char kBackgroundPageHTMLStart[] =
27 "<!DOCTYPE html>\n\
28 <html>\n\
29 <head><meta charset=\"utf-8\"></head>\n\
30 <body>";
31
32 static const char kBackgroundPageHTMLScript[] =
33 "\n\
34 <script type=\"text/javascript\" src=\"%s\"></script>";
35
36 static const char kBackgroundPageHTMLEnd[] =
37 "\n\
38 <body>\n\
39 </html>";
40
41 static const char kRestrictedDomainPref[] =
42 "extensions.webextensions.restrictedDomains";
43
EPS()44 static inline ExtensionPolicyService& EPS() {
45 return ExtensionPolicyService::GetSingleton();
46 }
47
Proto()48 static nsISubstitutingProtocolHandler* Proto() {
49 static nsCOMPtr<nsISubstitutingProtocolHandler> sHandler;
50
51 if (MOZ_UNLIKELY(!sHandler)) {
52 nsCOMPtr<nsIIOService> ios = do_GetIOService();
53 MOZ_RELEASE_ASSERT(ios);
54
55 nsCOMPtr<nsIProtocolHandler> handler;
56 ios->GetProtocolHandler(kProto, getter_AddRefs(handler));
57
58 sHandler = do_QueryInterface(handler);
59 MOZ_RELEASE_ASSERT(sHandler);
60
61 ClearOnShutdown(&sHandler);
62 }
63
64 return sHandler;
65 }
66
67 /*****************************************************************************
68 * WebExtensionPolicy
69 *****************************************************************************/
70
WebExtensionPolicy(GlobalObject & aGlobal,const WebExtensionInit & aInit,ErrorResult & aRv)71 WebExtensionPolicy::WebExtensionPolicy(GlobalObject& aGlobal,
72 const WebExtensionInit& aInit,
73 ErrorResult& aRv)
74 : mId(NS_AtomizeMainThread(aInit.mId)),
75 mHostname(aInit.mMozExtensionHostname),
76 mName(aInit.mName),
77 mContentSecurityPolicy(aInit.mContentSecurityPolicy),
78 mLocalizeCallback(aInit.mLocalizeCallback),
79 mPermissions(new AtomSet(aInit.mPermissions)),
80 mHostPermissions(aInit.mAllowedOrigins) {
81 mWebAccessiblePaths.AppendElements(aInit.mWebAccessibleResources);
82
83 if (!aInit.mBackgroundScripts.IsNull()) {
84 mBackgroundScripts.SetValue().AppendElements(
85 aInit.mBackgroundScripts.Value());
86 }
87
88 if (mContentSecurityPolicy.IsVoid()) {
89 EPS().DefaultCSP(mContentSecurityPolicy);
90 }
91
92 mContentScripts.SetCapacity(aInit.mContentScripts.Length());
93 for (const auto& scriptInit : aInit.mContentScripts) {
94 // The activeTab permission is only for dynamically injected scripts,
95 // it cannot be used for declarative content scripts.
96 if (scriptInit.mHasActiveTabPermission) {
97 aRv.Throw(NS_ERROR_INVALID_ARG);
98 return;
99 }
100
101 RefPtr<WebExtensionContentScript> contentScript =
102 new WebExtensionContentScript(*this, scriptInit, aRv);
103 if (aRv.Failed()) {
104 return;
105 }
106 mContentScripts.AppendElement(Move(contentScript));
107 }
108
109 nsresult rv = NS_NewURI(getter_AddRefs(mBaseURI), aInit.mBaseURL);
110 if (NS_FAILED(rv)) {
111 aRv.Throw(rv);
112 }
113 }
114
Constructor(GlobalObject & aGlobal,const WebExtensionInit & aInit,ErrorResult & aRv)115 already_AddRefed<WebExtensionPolicy> WebExtensionPolicy::Constructor(
116 GlobalObject& aGlobal, const WebExtensionInit& aInit, ErrorResult& aRv) {
117 RefPtr<WebExtensionPolicy> policy =
118 new WebExtensionPolicy(aGlobal, aInit, aRv);
119 if (aRv.Failed()) {
120 return nullptr;
121 }
122 return policy.forget();
123 }
124
GetActiveExtensions(dom::GlobalObject & aGlobal,nsTArray<RefPtr<WebExtensionPolicy>> & aResults)125 /* static */ void WebExtensionPolicy::GetActiveExtensions(
126 dom::GlobalObject& aGlobal,
127 nsTArray<RefPtr<WebExtensionPolicy>>& aResults) {
128 EPS().GetAll(aResults);
129 }
130
GetByID(dom::GlobalObject & aGlobal,const nsAString & aID)131 /* static */ already_AddRefed<WebExtensionPolicy> WebExtensionPolicy::GetByID(
132 dom::GlobalObject& aGlobal, const nsAString& aID) {
133 return do_AddRef(EPS().GetByID(aID));
134 }
135
136 /* static */ already_AddRefed<WebExtensionPolicy>
GetByHostname(dom::GlobalObject & aGlobal,const nsACString & aHostname)137 WebExtensionPolicy::GetByHostname(dom::GlobalObject& aGlobal,
138 const nsACString& aHostname) {
139 return do_AddRef(EPS().GetByHost(aHostname));
140 }
141
GetByURI(dom::GlobalObject & aGlobal,nsIURI * aURI)142 /* static */ already_AddRefed<WebExtensionPolicy> WebExtensionPolicy::GetByURI(
143 dom::GlobalObject& aGlobal, nsIURI* aURI) {
144 return do_AddRef(EPS().GetByURL(aURI));
145 }
146
SetActive(bool aActive,ErrorResult & aRv)147 void WebExtensionPolicy::SetActive(bool aActive, ErrorResult& aRv) {
148 if (aActive == mActive) {
149 return;
150 }
151
152 bool ok = aActive ? Enable() : Disable();
153
154 if (!ok) {
155 aRv.Throw(NS_ERROR_UNEXPECTED);
156 }
157 }
158
Enable()159 bool WebExtensionPolicy::Enable() {
160 MOZ_ASSERT(!mActive);
161
162 if (!EPS().RegisterExtension(*this)) {
163 return false;
164 }
165
166 Unused << Proto()->SetSubstitution(MozExtensionHostname(), mBaseURI);
167
168 mActive = true;
169 return true;
170 }
171
Disable()172 bool WebExtensionPolicy::Disable() {
173 MOZ_ASSERT(mActive);
174 MOZ_ASSERT(EPS().GetByID(Id()) == this);
175
176 if (!EPS().UnregisterExtension(*this)) {
177 return false;
178 }
179
180 Unused << Proto()->SetSubstitution(MozExtensionHostname(), nullptr);
181
182 mActive = false;
183 return true;
184 }
185
GetURL(const nsAString & aPath,nsAString & aResult,ErrorResult & aRv) const186 void WebExtensionPolicy::GetURL(const nsAString& aPath, nsAString& aResult,
187 ErrorResult& aRv) const {
188 auto result = GetURL(aPath);
189 if (result.isOk()) {
190 aResult = result.unwrap();
191 } else {
192 aRv.Throw(result.unwrapErr());
193 }
194 }
195
GetURL(const nsAString & aPath) const196 Result<nsString, nsresult> WebExtensionPolicy::GetURL(
197 const nsAString& aPath) const {
198 nsPrintfCString spec("%s://%s/", kProto, mHostname.get());
199
200 nsCOMPtr<nsIURI> uri;
201 MOZ_TRY(NS_NewURI(getter_AddRefs(uri), spec));
202
203 MOZ_TRY(uri->Resolve(NS_ConvertUTF16toUTF8(aPath), spec));
204
205 return NS_ConvertUTF8toUTF16(spec);
206 }
207
RegisterContentScript(WebExtensionContentScript & script,ErrorResult & aRv)208 void WebExtensionPolicy::RegisterContentScript(
209 WebExtensionContentScript& script, ErrorResult& aRv) {
210 // Raise an "invalid argument" error if the script is not related to
211 // the expected extension or if it is already registered.
212 if (script.mExtension != this || mContentScripts.Contains(&script)) {
213 aRv.Throw(NS_ERROR_INVALID_ARG);
214 return;
215 }
216
217 RefPtr<WebExtensionContentScript> newScript = &script;
218
219 if (!mContentScripts.AppendElement(Move(newScript), fallible)) {
220 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
221 return;
222 }
223
224 WebExtensionPolicyBinding::ClearCachedContentScriptsValue(this);
225 }
226
UnregisterContentScript(const WebExtensionContentScript & script,ErrorResult & aRv)227 void WebExtensionPolicy::UnregisterContentScript(
228 const WebExtensionContentScript& script, ErrorResult& aRv) {
229 if (script.mExtension != this || !mContentScripts.RemoveElement(&script)) {
230 aRv.Throw(NS_ERROR_INVALID_ARG);
231 return;
232 }
233
234 WebExtensionPolicyBinding::ClearCachedContentScriptsValue(this);
235 }
236
UseRemoteWebExtensions(GlobalObject & aGlobal)237 /* static */ bool WebExtensionPolicy::UseRemoteWebExtensions(
238 GlobalObject& aGlobal) {
239 return EPS().UseRemoteExtensions();
240 }
241
IsExtensionProcess(GlobalObject & aGlobal)242 /* static */ bool WebExtensionPolicy::IsExtensionProcess(
243 GlobalObject& aGlobal) {
244 return EPS().IsExtensionProcess();
245 }
246
247 namespace {
248 /**
249 * Maintains a dynamically updated AtomSet based on the comma-separated
250 * values in the given string pref.
251 */
252 class AtomSetPref : public nsIObserver, public nsSupportsWeakReference {
253 public:
254 NS_DECL_ISUPPORTS
255 NS_DECL_NSIOBSERVER
256
Create(const char * aPref)257 static already_AddRefed<AtomSetPref> Create(const char* aPref) {
258 RefPtr<AtomSetPref> self = new AtomSetPref(aPref);
259 Preferences::AddWeakObserver(self, aPref);
260 return self.forget();
261 }
262
263 const AtomSet& Get() const;
264
Contains(const nsAtom * aAtom) const265 bool Contains(const nsAtom* aAtom) const { return Get().Contains(aAtom); }
266
267 protected:
268 virtual ~AtomSetPref() = default;
269
AtomSetPref(const char * aPref)270 explicit AtomSetPref(const char* aPref) : mPref(aPref) {}
271
272 private:
273 mutable RefPtr<AtomSet> mAtomSet;
274 const char* mPref;
275 };
276
Get() const277 const AtomSet& AtomSetPref::Get() const {
278 if (!mAtomSet) {
279 nsAutoCString eltsString;
280 Unused << Preferences::GetCString(mPref, eltsString);
281
282 AutoTArray<nsString, 32> elts;
283 for (const nsACString& elt : eltsString.Split(',')) {
284 elts.AppendElement(NS_ConvertUTF8toUTF16(elt));
285 elts.LastElement().StripWhitespace();
286 }
287 mAtomSet = new AtomSet(elts);
288 }
289
290 return *mAtomSet;
291 }
292
293 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)294 AtomSetPref::Observe(nsISupports* aSubject, const char* aTopic,
295 const char16_t* aData) {
296 mAtomSet = nullptr;
297 return NS_OK;
298 }
299
300 NS_IMPL_ISUPPORTS(AtomSetPref, nsIObserver, nsISupportsWeakReference)
301 }; // namespace
302
IsRestrictedDoc(const DocInfo & aDoc)303 /* static */ bool WebExtensionPolicy::IsRestrictedDoc(const DocInfo& aDoc) {
304 // With the exception of top-level about:blank documents with null
305 // principals, we never match documents that have non-codebase principals,
306 // including those with null principals or system principals.
307 if (aDoc.Principal() && !aDoc.Principal()->GetIsCodebasePrincipal()) {
308 return true;
309 }
310
311 return IsRestrictedURI(aDoc.PrincipalURL());
312 }
313
IsRestrictedURI(const URLInfo & aURI)314 /* static */ bool WebExtensionPolicy::IsRestrictedURI(const URLInfo& aURI) {
315 static RefPtr<AtomSetPref> domains;
316 if (!domains) {
317 domains = AtomSetPref::Create(kRestrictedDomainPref);
318 ClearOnShutdown(&domains);
319 }
320
321 if (domains->Contains(aURI.HostAtom())) {
322 return true;
323 }
324
325 if (AddonManagerWebAPI::IsValidSite(aURI.URI())) {
326 return true;
327 }
328
329 return false;
330 }
331
BackgroundPageHTML() const332 nsCString WebExtensionPolicy::BackgroundPageHTML() const {
333 nsAutoCString result;
334
335 if (mBackgroundScripts.IsNull()) {
336 result.SetIsVoid(true);
337 return result;
338 }
339
340 result.AppendLiteral(kBackgroundPageHTMLStart);
341
342 for (auto& script : mBackgroundScripts.Value()) {
343 nsCString escaped;
344 nsAppendEscapedHTML(NS_ConvertUTF16toUTF8(script), escaped);
345
346 result.AppendPrintf(kBackgroundPageHTMLScript, escaped.get());
347 }
348
349 result.AppendLiteral(kBackgroundPageHTMLEnd);
350 return result;
351 }
352
Localize(const nsAString & aInput,nsString & aOutput) const353 void WebExtensionPolicy::Localize(const nsAString& aInput,
354 nsString& aOutput) const {
355 mLocalizeCallback->Call(aInput, aOutput);
356 }
357
WrapObject(JSContext * aCx,JS::HandleObject aGivenProto)358 JSObject* WebExtensionPolicy::WrapObject(JSContext* aCx,
359 JS::HandleObject aGivenProto) {
360 return WebExtensionPolicyBinding::Wrap(aCx, this, aGivenProto);
361 }
362
GetContentScripts(nsTArray<RefPtr<WebExtensionContentScript>> & aScripts) const363 void WebExtensionPolicy::GetContentScripts(
364 nsTArray<RefPtr<WebExtensionContentScript>>& aScripts) const {
365 aScripts.AppendElements(mContentScripts);
366 }
367
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionPolicy,mParent,mLocalizeCallback,mHostPermissions,mWebAccessiblePaths,mContentScripts)368 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionPolicy, mParent,
369 mLocalizeCallback, mHostPermissions,
370 mWebAccessiblePaths, mContentScripts)
371
372 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebExtensionPolicy)
373 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
374 NS_INTERFACE_MAP_ENTRY(nsISupports)
375 NS_INTERFACE_MAP_END
376
377 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebExtensionPolicy)
378 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebExtensionPolicy)
379
380 /*****************************************************************************
381 * WebExtensionContentScript
382 *****************************************************************************/
383
384 /* static */ already_AddRefed<WebExtensionContentScript>
385 WebExtensionContentScript::Constructor(GlobalObject& aGlobal,
386 WebExtensionPolicy& aExtension,
387 const ContentScriptInit& aInit,
388 ErrorResult& aRv) {
389 RefPtr<WebExtensionContentScript> script =
390 new WebExtensionContentScript(aExtension, aInit, aRv);
391 if (aRv.Failed()) {
392 return nullptr;
393 }
394 return script.forget();
395 }
396
WebExtensionContentScript(WebExtensionPolicy & aExtension,const ContentScriptInit & aInit,ErrorResult & aRv)397 WebExtensionContentScript::WebExtensionContentScript(
398 WebExtensionPolicy& aExtension, const ContentScriptInit& aInit,
399 ErrorResult& aRv)
400 : mExtension(&aExtension),
401 mHasActiveTabPermission(aInit.mHasActiveTabPermission),
402 mRestricted(!aExtension.HasPermission(nsGkAtoms::mozillaAddons)),
403 mMatches(aInit.mMatches),
404 mExcludeMatches(aInit.mExcludeMatches),
405 mCssPaths(aInit.mCssPaths),
406 mJsPaths(aInit.mJsPaths),
407 mRunAt(aInit.mRunAt),
408 mAllFrames(aInit.mAllFrames),
409 mFrameID(aInit.mFrameID),
410 mMatchAboutBlank(aInit.mMatchAboutBlank) {
411 if (!aInit.mIncludeGlobs.IsNull()) {
412 mIncludeGlobs.SetValue().AppendElements(aInit.mIncludeGlobs.Value());
413 }
414
415 if (!aInit.mExcludeGlobs.IsNull()) {
416 mExcludeGlobs.SetValue().AppendElements(aInit.mExcludeGlobs.Value());
417 }
418 }
419
Matches(const DocInfo & aDoc) const420 bool WebExtensionContentScript::Matches(const DocInfo& aDoc) const {
421 if (!mFrameID.IsNull()) {
422 if (aDoc.FrameID() != mFrameID.Value()) {
423 return false;
424 }
425 } else {
426 if (!mAllFrames && !aDoc.IsTopLevel()) {
427 return false;
428 }
429 }
430
431 if (!mMatchAboutBlank && aDoc.URL().InheritsPrincipal()) {
432 return false;
433 }
434
435 // Top-level about:blank is a special case. We treat it as a match if
436 // matchAboutBlank is true and it has the null principal. In all other
437 // cases, we test the URL of the principal that it inherits.
438 if (mMatchAboutBlank && aDoc.IsTopLevel() &&
439 aDoc.URL().Spec().EqualsLiteral("about:blank") && aDoc.Principal() &&
440 aDoc.Principal()->GetIsNullPrincipal()) {
441 return true;
442 }
443
444 if (mRestricted && mExtension->IsRestrictedDoc(aDoc)) {
445 return false;
446 }
447
448 auto& urlinfo = aDoc.PrincipalURL();
449 if (mHasActiveTabPermission && aDoc.ShouldMatchActiveTabPermission() &&
450 MatchPattern::MatchesAllURLs(urlinfo)) {
451 return true;
452 }
453
454 return MatchesURI(urlinfo);
455 }
456
MatchesURI(const URLInfo & aURL) const457 bool WebExtensionContentScript::MatchesURI(const URLInfo& aURL) const {
458 if (!mMatches->Matches(aURL)) {
459 return false;
460 }
461
462 if (mExcludeMatches && mExcludeMatches->Matches(aURL)) {
463 return false;
464 }
465
466 if (!mIncludeGlobs.IsNull() && !mIncludeGlobs.Value().Matches(aURL.Spec())) {
467 return false;
468 }
469
470 if (!mExcludeGlobs.IsNull() && mExcludeGlobs.Value().Matches(aURL.Spec())) {
471 return false;
472 }
473
474 if (mRestricted && mExtension->IsRestrictedURI(aURL)) {
475 return false;
476 }
477
478 return true;
479 }
480
WrapObject(JSContext * aCx,JS::HandleObject aGivenProto)481 JSObject* WebExtensionContentScript::WrapObject(JSContext* aCx,
482 JS::HandleObject aGivenProto) {
483 return WebExtensionContentScriptBinding::Wrap(aCx, this, aGivenProto);
484 }
485
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionContentScript,mMatches,mExcludeMatches,mIncludeGlobs,mExcludeGlobs,mExtension)486 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionContentScript, mMatches,
487 mExcludeMatches, mIncludeGlobs,
488 mExcludeGlobs, mExtension)
489
490 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebExtensionContentScript)
491 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
492 NS_INTERFACE_MAP_ENTRY(nsISupports)
493 NS_INTERFACE_MAP_END
494
495 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebExtensionContentScript)
496 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebExtensionContentScript)
497
498 /*****************************************************************************
499 * DocInfo
500 *****************************************************************************/
501
502 DocInfo::DocInfo(const URLInfo& aURL, nsILoadInfo* aLoadInfo)
503 : mURL(aURL), mObj(AsVariant(aLoadInfo)) {}
504
DocInfo(nsPIDOMWindowOuter * aWindow)505 DocInfo::DocInfo(nsPIDOMWindowOuter* aWindow)
506 : mURL(aWindow->GetDocumentURI()), mObj(AsVariant(aWindow)) {}
507
IsTopLevel() const508 bool DocInfo::IsTopLevel() const {
509 if (mIsTopLevel.isNothing()) {
510 struct Matcher {
511 bool match(Window aWin) { return aWin->IsTopLevelWindow(); }
512 bool match(LoadInfo aLoadInfo) { return aLoadInfo->GetIsTopLevelLoad(); }
513 };
514 mIsTopLevel.emplace(mObj.match(Matcher()));
515 }
516 return mIsTopLevel.ref();
517 }
518
WindowShouldMatchActiveTab(nsPIDOMWindowOuter * aWin)519 bool WindowShouldMatchActiveTab(nsPIDOMWindowOuter* aWin) {
520 if (aWin->IsTopLevelWindow()) {
521 return true;
522 }
523
524 nsIDocShell* docshell = aWin->GetDocShell();
525 if (!docshell || docshell->GetCreatedDynamically()) {
526 return false;
527 }
528
529 nsIDocument* doc = aWin->GetExtantDoc();
530 if (!doc) {
531 return false;
532 }
533
534 nsIChannel* channel = doc->GetChannel();
535 if (!channel) {
536 return false;
537 }
538
539 nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
540
541 if (!loadInfo) {
542 return false;
543 }
544
545 if (!loadInfo->GetOriginalFrameSrcLoad()) {
546 return false;
547 }
548
549 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin->GetParent();
550 MOZ_ASSERT(parent != nullptr);
551 return WindowShouldMatchActiveTab(parent);
552 }
553
ShouldMatchActiveTabPermission() const554 bool DocInfo::ShouldMatchActiveTabPermission() const {
555 struct Matcher {
556 bool match(Window aWin) { return WindowShouldMatchActiveTab(aWin); }
557 bool match(LoadInfo aLoadInfo) { return false; }
558 };
559 return mObj.match(Matcher());
560 }
561
FrameID() const562 uint64_t DocInfo::FrameID() const {
563 if (mFrameID.isNothing()) {
564 if (IsTopLevel()) {
565 mFrameID.emplace(0);
566 } else {
567 struct Matcher {
568 uint64_t match(Window aWin) { return aWin->WindowID(); }
569 uint64_t match(LoadInfo aLoadInfo) {
570 return aLoadInfo->GetOuterWindowID();
571 }
572 };
573 mFrameID.emplace(mObj.match(Matcher()));
574 }
575 }
576 return mFrameID.ref();
577 }
578
Principal() const579 nsIPrincipal* DocInfo::Principal() const {
580 if (mPrincipal.isNothing()) {
581 struct Matcher {
582 explicit Matcher(const DocInfo& aThis) : mThis(aThis) {}
583 const DocInfo& mThis;
584
585 nsIPrincipal* match(Window aWin) {
586 nsCOMPtr<nsIDocument> doc = aWin->GetDoc();
587 return doc->NodePrincipal();
588 }
589 nsIPrincipal* match(LoadInfo aLoadInfo) {
590 if (!(mThis.URL().InheritsPrincipal() ||
591 aLoadInfo->GetForceInheritPrincipal())) {
592 return nullptr;
593 }
594 if (auto principal = aLoadInfo->PrincipalToInherit()) {
595 return principal;
596 }
597 return aLoadInfo->TriggeringPrincipal();
598 }
599 };
600 mPrincipal.emplace(mObj.match(Matcher(*this)));
601 }
602 return mPrincipal.ref();
603 }
604
PrincipalURL() const605 const URLInfo& DocInfo::PrincipalURL() const {
606 if (!(Principal() && Principal()->GetIsCodebasePrincipal())) {
607 return URL();
608 }
609
610 if (mPrincipalURL.isNothing()) {
611 nsIPrincipal* prin = Principal();
612 nsCOMPtr<nsIURI> uri;
613 if (NS_SUCCEEDED(prin->GetURI(getter_AddRefs(uri)))) {
614 MOZ_DIAGNOSTIC_ASSERT(uri);
615 mPrincipalURL.emplace(uri);
616 } else {
617 mPrincipalURL.emplace(URL());
618 }
619 }
620
621 return mPrincipalURL.ref();
622 }
623
624 } // namespace extensions
625 } // namespace mozilla
626