1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_COOKIES_SITE_FOR_COOKIES_H_ 6 #define NET_COOKIES_SITE_FOR_COOKIES_H_ 7 8 #include <string> 9 10 #include "base/gtest_prod_util.h" 11 #include "base/strings/string_piece.h" 12 #include "net/base/net_export.h" 13 #include "net/base/schemeful_site.h" 14 #include "url/gurl.h" 15 #include "url/origin.h" 16 17 namespace net { 18 19 // Represents which origins are to be considered same-site for a given 20 // context (e.g. frame). There may be none. 21 // 22 // The currently implemented policy ("schemeful") is that 23 // two valid URLs would be considered same-site if either: 24 // 1) They both have compatible schemes along with non-empty and equal 25 // registrable domains or hostnames/IPs. Two schemes are compatible if they 26 // are either equal, or are both in {http, ws}, or are both in {https, wss}. 27 // E.x. "https://example.com" and "wss://example.com" 28 // 2) They both have empty hostnames and exactly equal schemes. E.x. "file://" 29 // and "file://" 30 // 31 // With the SchemefulSameSite feature disabled the policy ("schemeless") is that 32 // two valid URLs would be considered the same site if either: 1) They both have 33 // non-empty and equal registrable domains or hostnames/IPs. E.x. "example.com" 34 // and "example.com" 2) They both have empty hostnames and equal schemes. E.x. 35 // "file://" and "file://" 36 // 37 // 38 // Invalid URLs are never same-site to anything. 39 class NET_EXPORT SiteForCookies { 40 public: 41 // Matches nothing. 42 SiteForCookies(); 43 44 SiteForCookies(const SiteForCookies& other); 45 SiteForCookies(SiteForCookies&& other); 46 47 explicit SiteForCookies(const SchemefulSite& schemeful_site); 48 49 ~SiteForCookies(); 50 51 SiteForCookies& operator=(const SiteForCookies& other); 52 SiteForCookies& operator=(SiteForCookies&& other); 53 54 // Tries to construct an instance from (potentially untrusted) values of 55 // site() and schemefully_same() that got received over an RPC. 56 // 57 // Returns whether successful or not. Doesn't touch `*out` if false is 58 // returned. This returning `true` does not mean that whoever sent the values 59 // did not lie, merely that they are well-formed. 60 static bool FromWire(const SchemefulSite& site, 61 bool schemefully_same, 62 SiteForCookies* out); 63 64 // If the origin is opaque, returns SiteForCookies that matches nothing. 65 // 66 // If it's not opaque, returns one that matches URLs which are considered to 67 // be same-party as URLs from `origin`. 68 static SiteForCookies FromOrigin(const url::Origin& origin); 69 70 // Equivalent to FromOrigin(url::Origin::Create(url)). 71 static SiteForCookies FromUrl(const GURL& url); 72 73 // Returns a string with the values of the member variables. 74 // `schemefully_same` being false does not change the output. 75 std::string ToDebugString() const; 76 77 // Returns true if `url` should be considered first-party to the context 78 // `this` represents. 79 bool IsFirstParty(const GURL& url) const; 80 81 // Don't use this function unless you know what you're doing, if you're unsure 82 // you probably want IsFirstParty(). 83 // 84 // If `compute_schemefully` is true this function will return true if `url` 85 // should be considered first-party to the context `this` represents when the 86 // compatibility of the schemes are taken into account. 87 // 88 // If `compute_schemefully` is false this function will return true if `url` 89 // should be considered first-party to the context `this` represents when the 90 // compatibility of the scheme are not taken into account. Note that schemes 91 // are still compared for exact equality if neither `this` nor `url` have a 92 // registered domain. 93 bool IsFirstPartyWithSchemefulMode(const GURL& url, 94 bool compute_schemefully) const; 95 96 // Returns true if `other.IsFirstParty()` is true for exactly the same URLs 97 // as `this->IsFirstParty` (potentially none). Two SFCs are also considered 98 // equivalent if neither ever returns true for `IsFirstParty()`. I.e., both 99 // are null. 100 bool IsEquivalent(const SiteForCookies& other) const; 101 102 // Compares a "candidate" SFC, `this`, with an origin (represented as a 103 // SchemefulSite) from the frame tree and revises `this` to be null as 104 // required. 105 // 106 // This method is used when a sub-frame needs to have its SiteForCookies 107 // computed, which is dependent on all of its ancestors' origins (`other`). If 108 // its or any of its ancestors' frame's origins are not first-party with the 109 // top-level origin then this frame's SFC should be null. Otherwise, if it and 110 // all its ancestors are first-party with the top-level frame, the frame's 111 // SFC is the same as the top-level. 112 // 113 // This computation gets a bit tricky when considering "Schemeful Same-Site" 114 // as we don't know ahead of time if `this` is going to be used for a 115 // schemeful or schemeless computation later down the line, so we need to 116 // be careful to not completely nullify the entire SFC just because an `other` 117 // isn't schemefully first-party. If the computation is schemelessly 118 // first-party but *not schemefully* first-party then only the 119 // `schemefully_same_` flag will be cleared (which informs other functions to 120 // treat `this` as null for schemeful purposes). If the computation is not 121 // schemelessly first-party then `this` will have an opaque `site_` which 122 // completely nullifies it. 123 // 124 // This function should be called on all ancestors up to the top-level frame 125 // unless it returns false in which case `this` has been completely nullified 126 // and the caller may stop early. 127 // 128 // (This function's return value is the same as IsEquivalent() when "Schemeful 129 // Same-Site" is disabled.) 130 bool CompareWithFrameTreeSiteAndRevise(const SchemefulSite& other); 131 132 // Converts an Origin into a SchemefulSite and then calls 133 //`CompareWithFrameTreeSiteAndRevise(SchemefulSite)` 134 // 135 // If possible, prefer `CompareWithFrameTreeSiteAndRevise(SchemefulSite)` 136 // for performance reasons. 137 bool CompareWithFrameTreeOriginAndRevise(const url::Origin& other); 138 139 // Returns a URL that's first party to this SiteForCookies (an empty URL if 140 // none) --- that is, it has the property that 141 // site_for_cookies.IsEquivalent( 142 // SiteForCookies::FromUrl(site_for_cookies.RepresentativeUrl())); 143 // 144 // The convention used here (empty for nothing) is equivalent to that 145 // used before SiteForCookies existed as a type; this method is mostly 146 // meant to help incrementally migrate towards the type. New code probably 147 // should not need this. 148 GURL RepresentativeUrl() const; 149 site()150 const SchemefulSite& site() const { return site_; } 151 152 // Guaranteed to be lowercase. scheme()153 const std::string& scheme() const { return site_.site_as_origin_.scheme(); } 154 registrable_domain()155 const std::string& registrable_domain() const { 156 return site_.site_as_origin_.host(); 157 } 158 159 // Used for serialization/deserialization. This value is irrelevant if 160 // site().opaque() is true. schemefully_same()161 bool schemefully_same() const { return schemefully_same_; } 162 SetSchemefullySameForTesting(bool schemefully_same)163 void SetSchemefullySameForTesting(bool schemefully_same) { 164 schemefully_same_ = schemefully_same; 165 } 166 167 // Returns true if this SiteForCookies matches nothing. 168 // If the SchemefulSameSite feature is enabled then !schemefully_same_ causes 169 // this function to return true. 170 bool IsNull() const; 171 172 // Allows SiteForCookies to be used as a key in STL (for example, a std::set 173 // or std::map). 174 NET_EXPORT friend bool operator<(const SiteForCookies& lhs, 175 const SiteForCookies& rhs); 176 177 private: 178 FRIEND_TEST_ALL_PREFIXES(SiteForCookiesTest, SameScheme); 179 FRIEND_TEST_ALL_PREFIXES(SiteForCookiesTest, SameSchemeOpaque); 180 181 bool IsSchemefullyFirstParty(const GURL& url) const; 182 183 bool IsSchemelesslyFirstParty(const GURL& url) const; 184 185 // Sets the schemefully_same_ flag to false if other`'s scheme is 186 // cross-scheme to `this`. Schemes are considered cross-scheme if they're not 187 // compatible. Two schemes are compatible if they are either equal, or are 188 // both in {http, ws}, or are both in {https, wss}. 189 void MarkIfCrossScheme(const SchemefulSite& other); 190 191 // Represents the scheme and registrable domain of the site. The scheme should 192 // not be a WebSocket scheme; instead, ws is normalized to http, and 193 // wss is normalized to https upon construction. 194 SchemefulSite site_; 195 196 // Used to indicate if the SiteForCookies would be the same if computed 197 // schemefully. A schemeful computation means to take the scheme as well as 198 // the registrable_domain into account when determining same-siteness. 199 // See the class-level comment for more details on schemeless vs schemeful. 200 // 201 // True means to treat `this` as-is while false means that `this` should be 202 // treated as if it matches nothing i.e. IsNull() returns true. 203 // 204 // This value is important in the case where the SiteForCookies is being used 205 // to assess the first-partyness of a sub-frame in a document. 206 // 207 // For a SiteForCookies with !site_.opaque() this value starts as true and 208 // will only go false via MarkIfCrossScheme(), otherwise this value is 209 // irrelevant (For tests this value can also be modified by 210 // SetSchemefullySameForTesting()). 211 bool schemefully_same_ = false; 212 }; 213 214 } // namespace net 215 216 #endif // NET_COOKIES_SITE_FOR_COOKIES_H_ 217