Bug 1703443 - pt 6. Move RunNextCollectorTimer() into CCGCScheduler r=smaug
[gecko.git] / caps / ContentPrincipal.cpp
blobe57a889841fcf093d7bd00293af3fc13fb41c9ca
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ContentPrincipal.h"
9 #include "mozIThirdPartyUtil.h"
10 #include "nsContentUtils.h"
11 #include "nscore.h"
12 #include "nsScriptSecurityManager.h"
13 #include "nsString.h"
14 #include "nsReadableUtils.h"
15 #include "pratom.h"
16 #include "nsIURI.h"
17 #include "nsIURL.h"
18 #include "nsIStandardURL.h"
19 #include "nsIURIWithSpecialOrigin.h"
20 #include "nsIURIMutator.h"
21 #include "nsJSPrincipals.h"
22 #include "nsIEffectiveTLDService.h"
23 #include "nsIClassInfoImpl.h"
24 #include "nsIObjectInputStream.h"
25 #include "nsIObjectOutputStream.h"
26 #include "nsIProtocolHandler.h"
27 #include "nsError.h"
28 #include "nsIContentSecurityPolicy.h"
29 #include "nsNetCID.h"
30 #include "js/Wrapper.h"
32 #include "mozilla/dom/BlobURLProtocolHandler.h"
33 #include "mozilla/dom/ScriptSettings.h"
34 #include "mozilla/ClearOnShutdown.h"
35 #include "mozilla/ExtensionPolicyService.h"
36 #include "mozilla/Preferences.h"
37 #include "mozilla/HashFunctions.h"
39 #include "nsSerializationHelper.h"
40 #include "json/json.h"
42 using namespace mozilla;
44 static inline ExtensionPolicyService& EPS() {
45 return ExtensionPolicyService::GetSingleton();
48 NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
49 NS_PRINCIPAL_CID)
50 NS_IMPL_QUERY_INTERFACE_CI(ContentPrincipal, nsIPrincipal)
51 NS_IMPL_CI_INTERFACE_GETTER(ContentPrincipal, nsIPrincipal)
53 ContentPrincipal::ContentPrincipal(nsIURI* aURI,
54 const OriginAttributes& aOriginAttributes,
55 const nsACString& aOriginNoSuffix)
56 : BasePrincipal(eContentPrincipal, aOriginNoSuffix, aOriginAttributes),
57 mURI(aURI) {
58 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
59 // Assert that the URI we get here isn't any of the schemes that we know we
60 // should not get here. These schemes always either inherit their principal
61 // or fall back to a null principal. These are schemes which return
62 // URI_INHERITS_SECURITY_CONTEXT from their protocol handler's
63 // GetProtocolFlags function.
64 bool hasFlag = false;
65 MOZ_DIAGNOSTIC_ASSERT(
66 NS_SUCCEEDED(NS_URIChainHasFlags(
67 aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &hasFlag)) &&
68 !hasFlag);
69 #endif
72 ContentPrincipal::ContentPrincipal(ContentPrincipal* aOther,
73 const OriginAttributes& aOriginAttributes)
74 : BasePrincipal(aOther, aOriginAttributes),
75 mURI(aOther->mURI),
76 mDomain(aOther->mDomain),
77 mAddon(aOther->mAddon) {}
79 ContentPrincipal::~ContentPrincipal() = default;
81 nsresult ContentPrincipal::GetScriptLocation(nsACString& aStr) {
82 return mURI->GetSpec(aStr);
85 /* static */
86 nsresult ContentPrincipal::GenerateOriginNoSuffixFromURI(
87 nsIURI* aURI, nsACString& aOriginNoSuffix) {
88 if (!aURI) {
89 return NS_ERROR_FAILURE;
92 nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
93 if (!origin) {
94 return NS_ERROR_FAILURE;
97 MOZ_ASSERT(!NS_IsAboutBlank(origin),
98 "The inner URI for about:blank must be moz-safe-about:blank");
100 // Handle non-strict file:// uris.
101 if (!nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
102 NS_URIIsLocalFile(origin)) {
103 // If strict file origin policy is not in effect, all local files are
104 // considered to be same-origin, so return a known dummy origin here.
105 aOriginNoSuffix.AssignLiteral("file://UNIVERSAL_FILE_URI_ORIGIN");
106 return NS_OK;
109 nsresult rv;
110 // NB: This is only compiled for Thunderbird/Suite.
111 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
112 bool fullSpec = false;
113 rv = NS_URIChainHasFlags(origin, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC,
114 &fullSpec);
115 NS_ENSURE_SUCCESS(rv, rv);
116 if (fullSpec) {
117 return origin->GetAsciiSpec(aOriginNoSuffix);
119 #endif
121 // We want the invariant that prinA.origin == prinB.origin i.f.f.
122 // prinA.equals(prinB). However, this requires that we impose certain
123 // constraints on the behavior and origin semantics of principals, and in
124 // particular, forbid creating origin strings for principals whose equality
125 // constraints are not expressible as strings (i.e. object equality).
126 // Moreover, we want to forbid URIs containing the magic "^" we use as a
127 // separating character for origin attributes.
129 // These constraints can generally be achieved by restricting .origin to
130 // nsIStandardURL-based URIs, but there are a few other URI schemes that we
131 // need to handle.
132 if (origin->SchemeIs("about") ||
133 (origin->SchemeIs("moz-safe-about") &&
134 // We generally consider two about:foo origins to be same-origin, but
135 // about:blank is special since it can be generated from different
136 // sources. We check for moz-safe-about:blank since origin is an
137 // innermost URI.
138 !StringBeginsWith(origin->GetSpecOrDefault(),
139 "moz-safe-about:blank"_ns))) {
140 rv = origin->GetAsciiSpec(aOriginNoSuffix);
141 NS_ENSURE_SUCCESS(rv, rv);
143 int32_t pos = aOriginNoSuffix.FindChar('?');
144 int32_t hashPos = aOriginNoSuffix.FindChar('#');
146 if (hashPos != kNotFound && (pos == kNotFound || hashPos < pos)) {
147 pos = hashPos;
150 if (pos != kNotFound) {
151 aOriginNoSuffix.Truncate(pos);
154 // These URIs could technically contain a '^', but they never should.
155 if (NS_WARN_IF(aOriginNoSuffix.FindChar('^', 0) != -1)) {
156 aOriginNoSuffix.Truncate();
157 return NS_ERROR_FAILURE;
159 return NS_OK;
162 // This URL can be a blobURL. In this case, we should use the 'parent'
163 // principal instead.
164 nsCOMPtr<nsIPrincipal> blobPrincipal;
165 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
166 origin, getter_AddRefs(blobPrincipal))) {
167 MOZ_ASSERT(blobPrincipal);
168 return blobPrincipal->GetOriginNoSuffix(aOriginNoSuffix);
171 // If we reached this branch, we can only create an origin if we have a
172 // nsIStandardURL. So, we query to a nsIStandardURL, and fail if we aren't
173 // an instance of an nsIStandardURL nsIStandardURLs have the good property
174 // of escaping the '^' character in their specs, which means that we can be
175 // sure that the caret character (which is reserved for delimiting the end
176 // of the spec, and the beginning of the origin attributes) is not present
177 // in the origin string
178 nsCOMPtr<nsIStandardURL> standardURL = do_QueryInterface(origin);
179 if (!standardURL) {
180 return NS_ERROR_FAILURE;
183 // See whether we have a useful hostPort. If we do, use that.
184 nsAutoCString hostPort;
185 if (!origin->SchemeIs("chrome")) {
186 rv = origin->GetAsciiHostPort(hostPort);
187 NS_ENSURE_SUCCESS(rv, rv);
189 if (!hostPort.IsEmpty()) {
190 rv = origin->GetScheme(aOriginNoSuffix);
191 NS_ENSURE_SUCCESS(rv, rv);
192 aOriginNoSuffix.AppendLiteral("://");
193 aOriginNoSuffix.Append(hostPort);
194 return NS_OK;
197 rv = aURI->GetAsciiSpec(aOriginNoSuffix);
198 NS_ENSURE_SUCCESS(rv, rv);
200 // The origin, when taken from the spec, should not contain the ref part of
201 // the URL.
203 int32_t pos = aOriginNoSuffix.FindChar('?');
204 int32_t hashPos = aOriginNoSuffix.FindChar('#');
206 if (hashPos != kNotFound && (pos == kNotFound || hashPos < pos)) {
207 pos = hashPos;
210 if (pos != kNotFound) {
211 aOriginNoSuffix.Truncate(pos);
214 return NS_OK;
217 bool ContentPrincipal::SubsumesInternal(
218 nsIPrincipal* aOther,
219 BasePrincipal::DocumentDomainConsideration aConsideration) {
220 MOZ_ASSERT(aOther);
222 // For ContentPrincipal, Subsumes is equivalent to Equals.
223 if (aOther == this) {
224 return true;
227 // If either the subject or the object has changed its principal by
228 // explicitly setting document.domain then the other must also have
229 // done so in order to be considered the same origin. This prevents
230 // DNS spoofing based on document.domain (154930)
231 nsresult rv;
232 if (aConsideration == ConsiderDocumentDomain) {
233 // Get .domain on each principal.
234 nsCOMPtr<nsIURI> thisDomain, otherDomain;
235 GetDomain(getter_AddRefs(thisDomain));
236 aOther->GetDomain(getter_AddRefs(otherDomain));
238 // If either has .domain set, we have equality i.f.f. the domains match.
239 // Otherwise, we fall through to the non-document-domain-considering case.
240 if (thisDomain || otherDomain) {
241 bool isMatch =
242 nsScriptSecurityManager::SecurityCompareURIs(thisDomain, otherDomain);
243 #ifdef DEBUG
244 if (isMatch) {
245 nsAutoCString thisSiteOrigin, otherSiteOrigin;
246 MOZ_ALWAYS_SUCCEEDS(GetSiteOrigin(thisSiteOrigin));
247 MOZ_ALWAYS_SUCCEEDS(aOther->GetSiteOrigin(otherSiteOrigin));
248 MOZ_ASSERT(
249 thisSiteOrigin == otherSiteOrigin,
250 "SubsumesConsideringDomain passed with mismatched siteOrigin!");
252 #endif
253 return isMatch;
257 // Compare uris.
258 bool isSameOrigin = false;
259 rv = aOther->IsSameOrigin(mURI, false, &isSameOrigin);
260 NS_ENSURE_SUCCESS(rv, false);
261 return isSameOrigin;
264 NS_IMETHODIMP
265 ContentPrincipal::GetURI(nsIURI** aURI) {
266 *aURI = do_AddRef(mURI).take();
267 return NS_OK;
270 bool ContentPrincipal::MayLoadInternal(nsIURI* aURI) {
271 MOZ_ASSERT(aURI);
273 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
274 nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
275 do_QueryInterface(aURI);
276 if (uriWithSpecialOrigin) {
277 nsCOMPtr<nsIURI> origin;
278 nsresult rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
279 if (NS_WARN_IF(NS_FAILED(rv))) {
280 return false;
282 MOZ_ASSERT(origin);
283 OriginAttributes attrs;
284 RefPtr<BasePrincipal> principal =
285 BasePrincipal::CreateContentPrincipal(origin, attrs);
286 return nsIPrincipal::Subsumes(principal);
288 #endif
290 nsCOMPtr<nsIPrincipal> blobPrincipal;
291 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
292 aURI, getter_AddRefs(blobPrincipal))) {
293 MOZ_ASSERT(blobPrincipal);
294 return nsIPrincipal::Subsumes(blobPrincipal);
297 // If this principal is associated with an addon, check whether that addon
298 // has been given permission to load from this domain.
299 if (AddonAllowsLoad(aURI)) {
300 return true;
303 if (nsScriptSecurityManager::SecurityCompareURIs(mURI, aURI)) {
304 return true;
307 // If strict file origin policy is in effect, local files will always fail
308 // SecurityCompareURIs unless they are identical. Explicitly check file origin
309 // policy, in that case.
310 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
311 NS_URIIsLocalFile(aURI) && NS_RelaxStrictFileOriginPolicy(aURI, mURI)) {
312 return true;
315 return false;
318 uint32_t ContentPrincipal::GetHashValue() {
319 MOZ_ASSERT(mURI, "Need a principal URI");
321 nsCOMPtr<nsIURI> uri;
322 GetDomain(getter_AddRefs(uri));
323 if (!uri) {
324 GetURI(getter_AddRefs(uri));
326 return NS_SecurityHashURI(uri);
329 NS_IMETHODIMP
330 ContentPrincipal::GetDomain(nsIURI** aDomain) {
331 if (!mDomain) {
332 *aDomain = nullptr;
333 return NS_OK;
336 NS_ADDREF(*aDomain = mDomain);
337 return NS_OK;
340 NS_IMETHODIMP
341 ContentPrincipal::SetDomain(nsIURI* aDomain) {
342 MOZ_ASSERT(aDomain);
344 mDomain = aDomain;
345 SetHasExplicitDomain();
347 // Set the changed-document-domain flag on compartments containing realms
348 // using this principal.
349 auto cb = [](JSContext*, void*, JS::Realm* aRealm,
350 const JS::AutoRequireNoGC& nogc) {
351 JS::Compartment* comp = JS::GetCompartmentForRealm(aRealm);
352 xpc::SetCompartmentChangedDocumentDomain(comp);
354 JSPrincipals* principals =
355 nsJSPrincipals::get(static_cast<nsIPrincipal*>(this));
357 dom::AutoJSAPI jsapi;
358 jsapi.Init();
359 JS::IterateRealmsWithPrincipals(jsapi.cx(), principals, nullptr, cb);
361 return NS_OK;
364 static nsresult GetSpecialBaseDomain(const nsCOMPtr<nsIURI>& aURI,
365 bool* aHandled, nsACString& aBaseDomain) {
366 *aHandled = false;
368 // Special handling for a file URI.
369 if (NS_URIIsLocalFile(aURI)) {
370 // If strict file origin policy is not in effect, all local files are
371 // considered to be same-origin, so return a known dummy domain here.
372 if (!nsScriptSecurityManager::GetStrictFileOriginPolicy()) {
373 *aHandled = true;
374 aBaseDomain.AssignLiteral("UNIVERSAL_FILE_URI_ORIGIN");
375 return NS_OK;
378 // Otherwise, we return the file path.
379 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
381 if (url) {
382 *aHandled = true;
383 return url->GetFilePath(aBaseDomain);
387 bool hasNoRelativeFlag;
388 nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_NORELATIVE,
389 &hasNoRelativeFlag);
390 if (NS_WARN_IF(NS_FAILED(rv))) {
391 return rv;
394 // In case of FTP we want to get base domain via TLD service even if FTP
395 // protocol handler is disabled and the scheme is handled by external protocol
396 // handler which returns URI_NORELATIVE flag.
397 if (hasNoRelativeFlag && !aURI->SchemeIs("ftp")) {
398 *aHandled = true;
399 return aURI->GetSpec(aBaseDomain);
402 if (aURI->SchemeIs("indexeddb")) {
403 *aHandled = true;
404 return aURI->GetSpec(aBaseDomain);
407 return NS_OK;
410 NS_IMETHODIMP
411 ContentPrincipal::GetBaseDomain(nsACString& aBaseDomain) {
412 // Handle some special URIs first.
413 bool handled;
414 nsresult rv = GetSpecialBaseDomain(mURI, &handled, aBaseDomain);
415 NS_ENSURE_SUCCESS(rv, rv);
417 if (handled) {
418 return NS_OK;
421 // For everything else, we ask the TLD service via the ThirdPartyUtil.
422 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
423 do_GetService(THIRDPARTYUTIL_CONTRACTID);
424 if (!thirdPartyUtil) {
425 return NS_ERROR_FAILURE;
428 return thirdPartyUtil->GetBaseDomain(mURI, aBaseDomain);
431 NS_IMETHODIMP
432 ContentPrincipal::GetSiteOriginNoSuffix(nsACString& aSiteOrigin) {
433 nsresult rv = GetOriginNoSuffix(aSiteOrigin);
434 NS_ENSURE_SUCCESS(rv, rv);
436 // It is possible for two principals with the same origin to have different
437 // mURI values. In order to ensure that two principals with matching origins
438 // also have matching siteOrigins, we derive the siteOrigin entirely from the
439 // origin string and do not rely on mURI at all here.
440 nsCOMPtr<nsIURI> origin;
441 rv = NS_NewURI(getter_AddRefs(origin), aSiteOrigin);
442 if (NS_FAILED(rv)) {
443 // We got an error parsing the origin as a URI? siteOrigin == origin
444 // aSiteOrigin was already filled with `OriginNoSuffix`
445 return rv;
448 // Handle some special URIs first.
449 nsAutoCString baseDomain;
450 bool handled;
451 rv = GetSpecialBaseDomain(origin, &handled, baseDomain);
452 NS_ENSURE_SUCCESS(rv, rv);
454 if (handled) {
455 // This is a special URI ("file:", "about:", "view-source:", etc). Just
456 // return the origin.
457 return NS_OK;
460 // For everything else, we ask the TLD service. Note that, unlike in
461 // GetBaseDomain, we don't use ThirdPartyUtil.getBaseDomain because if the
462 // host is an IP address that returns the raw address and we can't use it with
463 // SetHost below because SetHost expects '[' and ']' around IPv6 addresses.
464 // See bug 1491728.
465 nsCOMPtr<nsIEffectiveTLDService> tldService =
466 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
467 if (!tldService) {
468 return NS_ERROR_FAILURE;
471 bool gotBaseDomain = false;
472 rv = tldService->GetBaseDomain(origin, 0, baseDomain);
473 if (NS_SUCCEEDED(rv)) {
474 gotBaseDomain = true;
475 } else {
476 // If this is an IP address or something like "localhost", we just continue
477 // with gotBaseDomain = false.
478 if (rv != NS_ERROR_HOST_IS_IP_ADDRESS &&
479 rv != NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
480 return rv;
484 // NOTE: Calling `SetHostPort` with a portless domain is insufficient to clear
485 // the port, so an extra `SetPort` call has to be made.
486 nsCOMPtr<nsIURI> siteUri;
487 NS_MutateURI mutator(origin);
488 mutator.SetUserPass(""_ns).SetPort(-1);
489 if (gotBaseDomain) {
490 mutator.SetHost(baseDomain);
492 rv = mutator.Finalize(siteUri);
493 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteUri");
494 NS_ENSURE_SUCCESS(rv, rv);
496 aSiteOrigin.Truncate();
497 rv = GenerateOriginNoSuffixFromURI(siteUri, aSiteOrigin);
498 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteOriginNoSuffix");
499 return rv;
502 nsresult ContentPrincipal::GetSiteIdentifier(SiteIdentifier& aSite) {
503 nsCString siteOrigin;
504 nsresult rv = GetSiteOrigin(siteOrigin);
505 NS_ENSURE_SUCCESS(rv, rv);
507 RefPtr<BasePrincipal> principal = CreateContentPrincipal(siteOrigin);
508 if (!principal) {
509 NS_WARNING("could not instantiate content principal");
510 return NS_ERROR_FAILURE;
513 aSite.Init(principal);
514 return NS_OK;
517 WebExtensionPolicy* ContentPrincipal::AddonPolicy() {
518 if (!mAddon.isSome()) {
519 NS_ENSURE_TRUE(mURI, nullptr);
521 if (mURI->SchemeIs("moz-extension")) {
522 mAddon.emplace(EPS().GetByURL(mURI.get()));
523 } else {
524 mAddon.emplace(nullptr);
528 return mAddon.value();
531 NS_IMETHODIMP
532 ContentPrincipal::GetAddonId(nsAString& aAddonId) {
533 auto* policy = AddonPolicy();
534 if (policy) {
535 policy->GetId(aAddonId);
536 } else {
537 aAddonId.Truncate();
539 return NS_OK;
542 NS_IMETHODIMP
543 ContentPrincipal::Deserializer::Read(nsIObjectInputStream* aStream) {
544 MOZ_ASSERT(!mPrincipal);
546 nsCOMPtr<nsISupports> supports;
547 nsCOMPtr<nsIURI> principalURI;
548 nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
549 if (NS_FAILED(rv)) {
550 return rv;
553 principalURI = do_QueryInterface(supports);
554 // Enforce re-parsing about: URIs so that if they change, we continue to use
555 // their new principals correctly.
556 if (principalURI->SchemeIs("about")) {
557 nsAutoCString spec;
558 principalURI->GetSpec(spec);
559 NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(principalURI), spec),
560 NS_ERROR_FAILURE);
563 nsCOMPtr<nsIURI> domain;
564 rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
565 if (NS_FAILED(rv)) {
566 return rv;
569 domain = do_QueryInterface(supports);
571 nsAutoCString suffix;
572 rv = aStream->ReadCString(suffix);
573 NS_ENSURE_SUCCESS(rv, rv);
575 OriginAttributes attrs;
576 bool ok = attrs.PopulateFromSuffix(suffix);
577 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
579 // Since Bug 965637 we do not serialize the CSP within the
580 // Principal anymore. Nevertheless there might still be
581 // serialized Principals that do have a serialized CSP.
582 // For now, we just read the CSP here but do not actually
583 // consume it. Please note that we deliberately ignore
584 // the return value to avoid CSP deserialization problems.
585 // After Bug 1508939 we will have a new serialization for
586 // Principals which allows us to update the code here.
587 // Additionally, the format for serialized CSPs changed
588 // within Bug 965637 which also can cause failures within
589 // the CSP deserialization code.
590 Unused << NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
592 nsAutoCString originNoSuffix;
593 rv = GenerateOriginNoSuffixFromURI(principalURI, originNoSuffix);
594 NS_ENSURE_SUCCESS(rv, rv);
596 RefPtr<ContentPrincipal> principal =
597 new ContentPrincipal(principalURI, attrs, originNoSuffix);
599 // Note: we don't call SetDomain here because we don't need the wrapper
600 // recomputation code there (we just created this principal).
601 if (domain) {
602 principal->mDomain = domain;
603 principal->SetHasExplicitDomain();
606 mPrincipal = principal.forget();
607 return NS_OK;
610 nsresult ContentPrincipal::PopulateJSONObject(Json::Value& aObject) {
611 nsAutoCString principalURI;
612 nsresult rv = mURI->GetSpec(principalURI);
613 NS_ENSURE_SUCCESS(rv, rv);
615 // We turn each int enum field into a JSON string key of the object
616 // aObject is the inner JSON object that has stringified enum keys
617 // An example aObject might be:
619 // eURI eSuffix
620 // | |
621 // {"0": "https://mozilla.com", "2": "^privateBrowsingId=1"}
622 // | | | |
623 // ----------------------------- |
624 // | | |
625 // Key ----------------------
626 // |
627 // Value
628 aObject[std::to_string(eURI)] = principalURI.get();
630 if (mDomain) {
631 nsAutoCString domainStr;
632 rv = mDomain->GetSpec(domainStr);
633 NS_ENSURE_SUCCESS(rv, rv);
634 aObject[std::to_string(eDomain)] = domainStr.get();
637 nsAutoCString suffix;
638 OriginAttributesRef().CreateSuffix(suffix);
639 if (suffix.Length() > 0) {
640 aObject[std::to_string(eSuffix)] = suffix.get();
643 return NS_OK;
646 already_AddRefed<BasePrincipal> ContentPrincipal::FromProperties(
647 nsTArray<ContentPrincipal::KeyVal>& aFields) {
648 MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
649 nsresult rv;
650 nsCOMPtr<nsIURI> principalURI;
651 nsCOMPtr<nsIURI> domain;
652 nsCOMPtr<nsIContentSecurityPolicy> csp;
653 OriginAttributes attrs;
655 // The odd structure here is to make the code to not compile
656 // if all the switch enum cases haven't been codified
657 for (const auto& field : aFields) {
658 switch (field.key) {
659 case ContentPrincipal::eURI:
660 if (!field.valueWasSerialized) {
661 MOZ_ASSERT(
662 false,
663 "Content principals require a principal URI in serialized JSON");
664 return nullptr;
666 rv = NS_NewURI(getter_AddRefs(principalURI), field.value.get());
667 NS_ENSURE_SUCCESS(rv, nullptr);
670 // Enforce re-parsing about: URIs so that if they change, we
671 // continue to use their new principals correctly.
672 if (principalURI->SchemeIs("about")) {
673 nsAutoCString spec;
674 principalURI->GetSpec(spec);
675 if (NS_FAILED(NS_NewURI(getter_AddRefs(principalURI), spec))) {
676 return nullptr;
680 break;
681 case ContentPrincipal::eDomain:
682 if (field.valueWasSerialized) {
683 rv = NS_NewURI(getter_AddRefs(domain), field.value.get());
684 NS_ENSURE_SUCCESS(rv, nullptr);
686 break;
687 case ContentPrincipal::eSuffix:
688 if (field.valueWasSerialized) {
689 bool ok = attrs.PopulateFromSuffix(field.value);
690 if (!ok) {
691 return nullptr;
694 break;
697 nsAutoCString originNoSuffix;
698 rv = ContentPrincipal::GenerateOriginNoSuffixFromURI(principalURI,
699 originNoSuffix);
700 if (NS_FAILED(rv)) {
701 return nullptr;
704 RefPtr<ContentPrincipal> principal =
705 new ContentPrincipal(principalURI, attrs, originNoSuffix);
707 principal->mDomain = domain;
708 if (principal->mDomain) {
709 principal->SetHasExplicitDomain();
712 return principal.forget();