Bug 1608150 [wpt PR 21112] - Add missing space in `./wpt lint` command line docs...
[gecko.git] / caps / OriginAttributes.cpp
blob79ab70b9074dbf0322501639a7b58e7eb322490d
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 "mozilla/OriginAttributes.h"
8 #include "mozilla/Preferences.h"
9 #include "mozilla/dom/BlobURLProtocolHandler.h"
10 #include "mozilla/dom/URLSearchParams.h"
11 #include "mozilla/dom/quota/QuotaManager.h"
12 #include "nsIEffectiveTLDService.h"
13 #include "nsIURI.h"
14 #include "nsURLHelper.h"
16 static const char kSourceChar = ':';
17 static const char kSanitizedChar = '+';
19 namespace mozilla {
21 using dom::URLParams;
23 void OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
24 nsIURI* aURI, bool aForced) {
25 bool isFirstPartyEnabled = IsFirstPartyEnabled();
27 // If the prefs are off or this is not a top level load, bail out.
28 if ((!isFirstPartyEnabled || !aIsTopLevelDocument) && !aForced) {
29 return;
32 nsCOMPtr<nsIEffectiveTLDService> tldService =
33 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
34 MOZ_ASSERT(tldService);
35 if (!tldService) {
36 return;
39 nsAutoCString baseDomain;
40 nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain);
41 if (NS_SUCCEEDED(rv)) {
42 mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
43 return;
46 if (rv == NS_ERROR_HOST_IS_IP_ADDRESS) {
47 // If the host is an IPv4/IPv6 address, we still accept it as a
48 // valid firstPartyDomain.
49 nsAutoCString ipAddr;
50 rv = aURI->GetHost(ipAddr);
51 NS_ENSURE_SUCCESS_VOID(rv);
53 if (net_IsValidIPv6Addr(ipAddr)) {
54 // According to RFC2732, the host of an IPv6 address should be an
55 // IPv6reference. The GetHost() of nsIURI will only return the IPv6
56 // address. So, we need to convert it back to IPv6reference here.
57 mFirstPartyDomain.Truncate();
58 mFirstPartyDomain.AssignLiteral("[");
59 mFirstPartyDomain.Append(NS_ConvertUTF8toUTF16(ipAddr));
60 mFirstPartyDomain.AppendLiteral("]");
61 } else {
62 mFirstPartyDomain = NS_ConvertUTF8toUTF16(ipAddr);
65 return;
68 // Saving isInsufficientDomainLevels before rv is overwritten.
69 bool isInsufficientDomainLevels = (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS);
70 nsAutoCString scheme;
71 if (aURI) {
72 rv = aURI->GetScheme(scheme);
73 NS_ENSURE_SUCCESS_VOID(rv);
74 if (scheme.EqualsLiteral("about")) {
75 mFirstPartyDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
76 return;
80 // Add-on principals should never get any first-party domain
81 // attributes in order to guarantee their storage integrity when switching
82 // FPI on and off.
83 if (scheme.EqualsLiteral("moz-extension")) {
84 return;
87 nsCOMPtr<nsIPrincipal> blobPrincipal;
88 if (aURI && dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
89 aURI, getter_AddRefs(blobPrincipal))) {
90 MOZ_ASSERT(blobPrincipal);
91 mFirstPartyDomain = blobPrincipal->OriginAttributesRef().mFirstPartyDomain;
92 return;
95 if (isInsufficientDomainLevels) {
96 nsAutoCString publicSuffix;
97 rv = tldService->GetPublicSuffix(aURI, publicSuffix);
98 if (NS_SUCCEEDED(rv)) {
99 mFirstPartyDomain = NS_ConvertUTF8toUTF16(publicSuffix);
101 return;
105 void OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
106 const nsACString& aDomain) {
107 SetFirstPartyDomain(aIsTopLevelDocument, NS_ConvertUTF8toUTF16(aDomain));
110 void OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
111 const nsAString& aDomain) {
112 bool isFirstPartyEnabled = IsFirstPartyEnabled();
114 // If the pref is off or this is not a top level load, bail out.
115 if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
116 return;
119 mFirstPartyDomain = aDomain;
122 void OriginAttributes::CreateSuffix(nsACString& aStr) const {
123 URLParams params;
124 nsAutoString value;
127 // Important: While serializing any string-valued attributes, perform a
128 // release-mode assertion to make sure that they don't contain characters that
129 // will break the quota manager when it uses the serialization for file
130 // naming.
133 if (mInIsolatedMozBrowser) {
134 params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
137 if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
138 value.Truncate();
139 value.AppendInt(mUserContextId);
140 params.Set(NS_LITERAL_STRING("userContextId"), value);
143 if (mPrivateBrowsingId) {
144 value.Truncate();
145 value.AppendInt(mPrivateBrowsingId);
146 params.Set(NS_LITERAL_STRING("privateBrowsingId"), value);
149 if (!mFirstPartyDomain.IsEmpty()) {
150 nsAutoString sanitizedFirstPartyDomain(mFirstPartyDomain);
151 sanitizedFirstPartyDomain.ReplaceChar(kSourceChar, kSanitizedChar);
153 params.Set(NS_LITERAL_STRING("firstPartyDomain"),
154 sanitizedFirstPartyDomain);
157 if (!mGeckoViewSessionContextId.IsEmpty()) {
158 nsAutoString sanitizedGeckoViewUserContextId(mGeckoViewSessionContextId);
159 sanitizedGeckoViewUserContextId.ReplaceChar(
160 dom::quota::QuotaManager::kReplaceChars, kSanitizedChar);
162 params.Set(NS_LITERAL_STRING("geckoViewUserContextId"),
163 sanitizedGeckoViewUserContextId);
166 aStr.Truncate();
168 params.Serialize(value);
169 if (!value.IsEmpty()) {
170 aStr.AppendLiteral("^");
171 aStr.Append(NS_ConvertUTF16toUTF8(value));
174 // In debug builds, check the whole string for illegal characters too (just in
175 // case).
176 #ifdef DEBUG
177 nsAutoCString str;
178 str.Assign(aStr);
179 MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) ==
180 kNotFound);
181 #endif
184 void OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const {
185 OriginAttributes attrs = *this;
187 if (!attrs.mFirstPartyDomain.IsEmpty()) {
188 attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_");
191 attrs.CreateSuffix(aStr);
194 namespace {
196 class MOZ_STACK_CLASS PopulateFromSuffixIterator final
197 : public URLParams::ForEachIterator {
198 public:
199 explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
200 : mOriginAttributes(aOriginAttributes) {
201 MOZ_ASSERT(aOriginAttributes);
202 // If a non-default mPrivateBrowsingId is passed and is not present in the
203 // suffix, then it will retain the id when it should be default according
204 // to the suffix. Set to default before iterating to fix this.
205 mOriginAttributes->mPrivateBrowsingId =
206 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
209 bool URLParamsIterator(const nsAString& aName,
210 const nsAString& aValue) override {
211 if (aName.EqualsLiteral("inBrowser")) {
212 if (!aValue.EqualsLiteral("1")) {
213 return false;
216 mOriginAttributes->mInIsolatedMozBrowser = true;
217 return true;
220 if (aName.EqualsLiteral("addonId") || aName.EqualsLiteral("appId")) {
221 // No longer supported. Silently ignore so that legacy origin strings
222 // don't cause failures.
223 return true;
226 if (aName.EqualsLiteral("userContextId")) {
227 nsresult rv;
228 int64_t val = aValue.ToInteger64(&rv);
229 NS_ENSURE_SUCCESS(rv, false);
230 NS_ENSURE_TRUE(val <= UINT32_MAX, false);
231 mOriginAttributes->mUserContextId = static_cast<uint32_t>(val);
233 return true;
236 if (aName.EqualsLiteral("privateBrowsingId")) {
237 nsresult rv;
238 int64_t val = aValue.ToInteger64(&rv);
239 NS_ENSURE_SUCCESS(rv, false);
240 NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false);
241 mOriginAttributes->mPrivateBrowsingId = static_cast<uint32_t>(val);
243 return true;
246 if (aName.EqualsLiteral("firstPartyDomain")) {
247 MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
248 nsAutoString firstPartyDomain(aValue);
249 firstPartyDomain.ReplaceChar(kSanitizedChar, kSourceChar);
250 mOriginAttributes->mFirstPartyDomain.Assign(firstPartyDomain);
251 return true;
254 if (aName.EqualsLiteral("geckoViewUserContextId")) {
255 MOZ_RELEASE_ASSERT(
256 mOriginAttributes->mGeckoViewSessionContextId.IsEmpty());
257 mOriginAttributes->mGeckoViewSessionContextId.Assign(aValue);
258 return true;
261 // No other attributes are supported.
262 return false;
265 private:
266 OriginAttributes* mOriginAttributes;
269 } // namespace
271 bool OriginAttributes::PopulateFromSuffix(const nsACString& aStr) {
272 if (aStr.IsEmpty()) {
273 return true;
276 if (aStr[0] != '^') {
277 return false;
280 PopulateFromSuffixIterator iterator(this);
281 return URLParams::Parse(Substring(aStr, 1, aStr.Length() - 1), iterator);
284 bool OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
285 nsACString& aOriginNoSuffix) {
286 // RFindChar is only available on nsCString.
287 nsCString origin(aOrigin);
288 int32_t pos = origin.RFindChar('^');
290 if (pos == kNotFound) {
291 aOriginNoSuffix = origin;
292 return true;
295 aOriginNoSuffix = Substring(origin, 0, pos);
296 return PopulateFromSuffix(Substring(origin, pos));
299 void OriginAttributes::SyncAttributesWithPrivateBrowsing(
300 bool aInPrivateBrowsing) {
301 mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0;
304 /* static */
305 bool OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin) {
306 nsAutoCString dummy;
307 OriginAttributes attrs;
308 if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) {
309 return false;
312 return !!attrs.mPrivateBrowsingId;
315 } // namespace mozilla