site_for_cookies.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/cookies/site_for_cookies.h"
  5. #include <utility>
  6. #include "base/strings/strcat.h"
  7. #include "base/strings/string_util.h"
  8. #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  9. #include "net/cookies/cookie_util.h"
  10. namespace net {
  11. SiteForCookies::SiteForCookies() = default;
  12. SiteForCookies::SiteForCookies(const SchemefulSite& site)
  13. : site_(site), schemefully_same_(!site.opaque()) {
  14. site_.ConvertWebSocketToHttp();
  15. }
  16. SiteForCookies::SiteForCookies(const SiteForCookies& other) = default;
  17. SiteForCookies::SiteForCookies(SiteForCookies&& other) = default;
  18. SiteForCookies::~SiteForCookies() = default;
  19. SiteForCookies& SiteForCookies::operator=(const SiteForCookies& other) =
  20. default;
  21. SiteForCookies& SiteForCookies::operator=(SiteForCookies&& site_for_cookies) =
  22. default;
  23. // static
  24. bool SiteForCookies::FromWire(const SchemefulSite& site,
  25. bool schemefully_same,
  26. SiteForCookies* out) {
  27. SiteForCookies candidate(site);
  28. if (site != candidate.site_)
  29. return false;
  30. candidate.schemefully_same_ = schemefully_same;
  31. *out = std::move(candidate);
  32. return true;
  33. }
  34. // static
  35. SiteForCookies SiteForCookies::FromOrigin(const url::Origin& origin) {
  36. return SiteForCookies(SchemefulSite(origin));
  37. }
  38. // static
  39. SiteForCookies SiteForCookies::FromUrl(const GURL& url) {
  40. return SiteForCookies::FromOrigin(url::Origin::Create(url));
  41. }
  42. std::string SiteForCookies::ToDebugString() const {
  43. std::string same_scheme_string = schemefully_same_ ? "true" : "false";
  44. return base::StrCat({"SiteForCookies: {site=", site_.Serialize(),
  45. "; schemefully_same=", same_scheme_string, "}"});
  46. }
  47. bool SiteForCookies::IsFirstParty(const GURL& url) const {
  48. return IsFirstPartyWithSchemefulMode(
  49. url, cookie_util::IsSchemefulSameSiteEnabled());
  50. }
  51. bool SiteForCookies::IsFirstPartyWithSchemefulMode(
  52. const GURL& url,
  53. bool compute_schemefully) const {
  54. if (compute_schemefully)
  55. return IsSchemefullyFirstParty(url);
  56. return IsSchemelesslyFirstParty(url);
  57. }
  58. bool SiteForCookies::IsEquivalent(const SiteForCookies& other) const {
  59. if (IsNull() || other.IsNull()) {
  60. // We need to check if `other.IsNull()` explicitly in order to catch if
  61. // `other.schemefully_same_` is false when "Schemeful Same-Site" is enabled.
  62. return IsNull() && other.IsNull();
  63. }
  64. // In the case where the site has no registrable domain or host, the scheme
  65. // cannot be ws(s) or http(s), so equality of sites implies actual equality of
  66. // schemes (not just modulo ws-http and wss-https compatibility).
  67. if (cookie_util::IsSchemefulSameSiteEnabled() ||
  68. !site_.has_registrable_domain_or_host()) {
  69. return site_ == other.site_;
  70. }
  71. return site_.SchemelesslyEqual(other.site_);
  72. }
  73. bool SiteForCookies::CompareWithFrameTreeSiteAndRevise(
  74. const SchemefulSite& other) {
  75. // Two opaque SFC are considered equivalent.
  76. if (site_.opaque() && other.opaque())
  77. return true;
  78. // But if only one is opaque we should return false.
  79. if (site_.opaque())
  80. return false;
  81. // Nullify `this` if the `other` is opaque
  82. if (other.opaque()) {
  83. site_ = SchemefulSite();
  84. return false;
  85. }
  86. bool nullify = site_.has_registrable_domain_or_host()
  87. ? !site_.SchemelesslyEqual(other)
  88. : site_ != other;
  89. if (nullify) {
  90. // We should only nullify this SFC if the registrable domains (or the entire
  91. // site for cases without an RD) don't match. We *should not* nullify if
  92. // only the schemes mismatch (unless there is no RD) because cookies may be
  93. // processed with LEGACY semantics which only use the RDs. Eventually, when
  94. // schemeful same-site can no longer be disabled, we can revisit this.
  95. site_ = SchemefulSite();
  96. return false;
  97. }
  98. MarkIfCrossScheme(other);
  99. return true;
  100. }
  101. bool SiteForCookies::CompareWithFrameTreeOriginAndRevise(
  102. const url::Origin& other) {
  103. return CompareWithFrameTreeSiteAndRevise(SchemefulSite(other));
  104. }
  105. GURL SiteForCookies::RepresentativeUrl() const {
  106. if (IsNull())
  107. return GURL();
  108. // Cannot use url::Origin::GetURL() because it loses the hostname for file:
  109. // scheme origins.
  110. GURL result(base::StrCat({scheme(), "://", registrable_domain(), "/"}));
  111. DCHECK(result.is_valid());
  112. return result;
  113. }
  114. bool SiteForCookies::IsNull() const {
  115. if (cookie_util::IsSchemefulSameSiteEnabled())
  116. return site_.opaque() || !schemefully_same_;
  117. return site_.opaque();
  118. }
  119. bool SiteForCookies::IsSchemefullyFirstParty(const GURL& url) const {
  120. // Can't use IsNull() as we want the same behavior regardless of
  121. // SchemefulSameSite feature status.
  122. if (site_.opaque() || !schemefully_same_ || !url.is_valid())
  123. return false;
  124. SchemefulSite other_site(url);
  125. other_site.ConvertWebSocketToHttp();
  126. return site_ == other_site;
  127. }
  128. bool SiteForCookies::IsSchemelesslyFirstParty(const GURL& url) const {
  129. // Can't use IsNull() as we want the same behavior regardless of
  130. // SchemefulSameSite feature status.
  131. if (site_.opaque() || !url.is_valid())
  132. return false;
  133. // We don't need to bother changing WebSocket schemes to http, because if
  134. // there is no registrable domain or host, the scheme cannot be ws(s) or
  135. // http(s), and the latter comparison is schemeless anyway.
  136. SchemefulSite other_site(url);
  137. if (!site_.has_registrable_domain_or_host())
  138. return site_ == other_site;
  139. return site_.SchemelesslyEqual(other_site);
  140. }
  141. void SiteForCookies::MarkIfCrossScheme(const SchemefulSite& other) {
  142. // If `this` is IsNull() then `this` doesn't match anything which means that
  143. // the scheme check is pointless. Also exit early if schemefully_same_ is
  144. // already false.
  145. if (IsNull() || !schemefully_same_)
  146. return;
  147. // Mark if `other` is opaque. Opaque origins shouldn't match.
  148. if (other.opaque()) {
  149. schemefully_same_ = false;
  150. return;
  151. }
  152. // Conversion to http/https should have occurred during construction.
  153. DCHECK_NE(url::kWsScheme, scheme());
  154. DCHECK_NE(url::kWssScheme, scheme());
  155. // If the schemes are equal, modulo ws-http and wss-https, don't mark.
  156. if (scheme() == other.site_as_origin_.scheme() ||
  157. (scheme() == url::kHttpsScheme &&
  158. other.site_as_origin_.scheme() == url::kWssScheme) ||
  159. (scheme() == url::kHttpScheme &&
  160. other.site_as_origin_.scheme() == url::kWsScheme)) {
  161. return;
  162. }
  163. // Mark that the two are cross-scheme to each other.
  164. schemefully_same_ = false;
  165. }
  166. bool operator<(const SiteForCookies& lhs, const SiteForCookies& rhs) {
  167. // Similar to IsEquivalent(), if they're both null then they're equivalent
  168. // and therefore `lhs` is not < `rhs`.
  169. if (lhs.IsNull() && rhs.IsNull())
  170. return false;
  171. // If only `lhs` is null then it's always < `rhs`.
  172. if (lhs.IsNull())
  173. return true;
  174. // If only `rhs` is null then `lhs` is not < `rhs`.
  175. if (rhs.IsNull())
  176. return false;
  177. // Otherwise neither are null and we need to compare the `site_`s.
  178. return lhs.site_ < rhs.site_;
  179. }
  180. } // namespace net