xref: /aosp_15_r20/external/cronet/net/cookies/site_for_cookies.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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