• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 // Brought to you by number 42.
6 
7 #ifndef NET_COOKIES_COOKIE_OPTIONS_H_
8 #define NET_COOKIES_COOKIE_OPTIONS_H_
9 
10 #include <ostream>
11 #include <string>
12 
13 #include "net/base/net_export.h"
14 #include "net/cookies/cookie_constants.h"
15 #include "net/cookies/cookie_inclusion_status.h"
16 #include "net/first_party_sets/same_party_context.h"
17 #include "url/gurl.h"
18 
19 namespace net {
20 
21 class NET_EXPORT CookieOptions {
22  public:
23 
24   // Relation between the cookie and the navigational environment.
25   class NET_EXPORT SameSiteCookieContext {
26    public:
27     // CROSS_SITE to SAME_SITE_STRICT are ordered from least to most trusted
28     // environment. Don't renumber, used in histograms.
29     enum class ContextType {
30       CROSS_SITE = 0,
31       // Same rules as lax but the http method is unsafe.
32       SAME_SITE_LAX_METHOD_UNSAFE = 1,
33       SAME_SITE_LAX = 2,
34       SAME_SITE_STRICT = 3,
35 
36       // Keep last, used for histograms.
37       COUNT
38     };
39 
40     // Holds metadata about the factors that went into deciding the ContextType.
41     //
42     // These values may be used for recording histograms or
43     // CookieInclusionStatus warnings, but SHOULD NOT be relied
44     // upon for cookie inclusion decisions. Use only the ContextTypes for that.
45     //
46     // When adding a field, also update CompleteEquivalenceForTesting.
47     struct NET_EXPORT ContextMetadata {
48       // Possible "downgrades" for the SameSite context type, e.g. from a more
49       // trusted context to a less trusted context, as a result of some behavior
50       // change affecting the same-site calculation.
51       enum class ContextDowngradeType {
52         // Context not downgraded.
53         kNoDowngrade,
54         // Context was originally strictly same-site, was downgraded to laxly
55         // same-site.
56         kStrictToLax,
57         // Context was originally strictly same-site, was downgraded to
58         // cross-site.
59         kStrictToCross,
60         // Context was originally laxly same-site, was downgraded to cross-site.
61         kLaxToCross,
62       };
63 
64       // These values are persisted to logs. Entries should not be renumbered
65       // and numeric values should never be reused.
66       // This enum is to help collect metrics for https://crbug.com/1221316.
67       // Specifically it's to help indicate how many cookies are accessed with a
68       // given redirect type in order to provide a denominator for the
69       // Cookie.CrossSiteRedirectDowngradeChangesInclusion2.* metrics.
70       // Note: for this enum the notation A->B->C means that a navigation from
71       // A to B was redirected to C. I.e.: A is the initator of the navigation
72       // and C is the final url.
73       enum class ContextRedirectTypeBug1221316 {
74         kUnset =
75             0,  // Indicates this value was unused and shouldn't be read. E.x.:
76                 // A javascript access means this value is meaningless.
77         kNoRedirect = 1,  // There weren't any redirects. E.x.: A->B, A->A
78         kCrossSiteRedirect =
79             2,  // There was a redirect but it didn't start and
80                 // end at the same site or the redirect was to a different site
81                 // than the site-for-cookies. E.x.: A->B->C or B->B->B when the
82                 // site-for-cookies is A.
83         kPartialSameSiteRedirect =
84             3,  // There was a redirect and the start and
85                 // end are the same site. E.x.: A->B->A. Only this one could
86                 // potentially set cross_site_redirect_downgrade.
87         kAllSameSiteRedirect = 4,  // There was a redirect and all urls are the
88                                    // same site. E.x.:, A->A->A
89         kMaxValue = kAllSameSiteRedirect
90       };
91 
92       // These values are persisted to logs. Entries should not be renumbered
93       // and numeric values should never be reused.
94       enum class HttpMethod {
95         // kUnset indicates this enum wasn't applicable in the context.
96         kUnset = -1,
97         // kUnknown indicates we were unable to convert the method string to
98         // this enum.
99         kUnknown = 0,
100         kGet = 1,
101         kHead = 2,
102         kPost = 3,
103         KPut = 4,
104         kDelete = 5,
105         kConnect = 6,
106         kOptions = 7,
107         kTrace = 8,
108         kPatch = 9,
109         kMaxValue = kPatch
110       };
111 
112       // Records the type of any context downgrade due to a cross-site redirect,
113       // i.e. whether the spec change in
114       // https://github.com/httpwg/http-extensions/pull/1348 changed the result
115       // of the context calculation. Note that a lax-to-cross downgrade can only
116       // happen for response cookies, because a laxly same-site context only
117       // happens for a top-level cross-site request, which cannot be downgraded
118       // due to a cross-site redirect to a non-top-level cross-site request.
119       // This only records whether the context was downgraded, not whether the
120       // cookie's inclusion result was changed.
121       ContextDowngradeType cross_site_redirect_downgrade =
122           ContextDowngradeType::kNoDowngrade;
123 
124       ContextRedirectTypeBug1221316 redirect_type_bug_1221316 =
125           ContextRedirectTypeBug1221316::kUnset;
126 
127       // Records the HTTP method of requests that result in a cross-site
128       // redirect downgrade. May be kUnset if there wasn't a downgrade or if the
129       // cookie access wasn't due to a request.
130       //
131       // Note that this field is always set when there was a context
132       // downgrade but the associated histrogram is only recorded when that
133       // context downgrade results in a change in inclusion status.
134       HttpMethod http_method_bug_1221316 = HttpMethod::kUnset;
135     };
136 
137     // The following three constructors apply default values for the metadata
138     // members.
SameSiteCookieContext()139     SameSiteCookieContext()
140         : SameSiteCookieContext(ContextType::CROSS_SITE,
141                                 ContextType::CROSS_SITE) {}
142 
SameSiteCookieContext(ContextType same_site_context)143     explicit SameSiteCookieContext(ContextType same_site_context)
144         : SameSiteCookieContext(same_site_context, same_site_context) {}
145 
SameSiteCookieContext(ContextType same_site_context,ContextType schemeful_same_site_context)146     SameSiteCookieContext(ContextType same_site_context,
147                           ContextType schemeful_same_site_context)
148         : SameSiteCookieContext(same_site_context,
149                                 schemeful_same_site_context,
150                                 ContextMetadata(),
151                                 ContextMetadata()) {}
152 
153     // Schemeful and schemeless context types are consistency-checked against
154     // each other, but the metadata is stored as-is (i.e. the values in
155     // `metadata` and `schemeful_metadata` may be logically inconsistent), as
156     // the metadata is not relied upon for correctness.
SameSiteCookieContext(ContextType same_site_context,ContextType schemeful_same_site_context,ContextMetadata metadata,ContextMetadata schemeful_metadata)157     SameSiteCookieContext(ContextType same_site_context,
158                           ContextType schemeful_same_site_context,
159                           ContextMetadata metadata,
160                           ContextMetadata schemeful_metadata)
161         : context_(same_site_context),
162           schemeful_context_(schemeful_same_site_context),
163           metadata_(metadata),
164           schemeful_metadata_(schemeful_metadata) {
165       DCHECK_LE(schemeful_context_, context_);
166     }
167 
168     // Convenience method which returns a SameSiteCookieContext with the most
169     // inclusive contexts. This allows access to all SameSite cookies.
170     static SameSiteCookieContext MakeInclusive();
171 
172     // Convenience method which returns a SameSiteCookieContext with the most
173     // inclusive contexts for set. This allows setting all SameSite cookies.
174     static SameSiteCookieContext MakeInclusiveForSet();
175 
176     // Returns the context for determining SameSite cookie inclusion.
177     ContextType GetContextForCookieInclusion() const;
178 
179     // Returns the metadata describing how this context was calculated, under
180     // the currently applicable schemeful/schemeless mode.
181     // TODO(chlily): Should take the CookieAccessSemantics as well, to
182     // accurately account for the context actually used for a given cookie.
183     const ContextMetadata& GetMetadataForCurrentSchemefulMode() const;
184 
185     // If you're just trying to determine if a cookie is accessible you likely
186     // want to use GetContextForCookieInclusion() which will return the correct
187     // context regardless the status of same-site features.
context()188     ContextType context() const { return context_; }
schemeful_context()189     ContextType schemeful_context() const { return schemeful_context_; }
190 
191     // You probably want to use GetMetadataForCurrentSchemefulMode() instead of
192     // these getters, since that takes into account the applicable schemeful
193     // mode.
metadata()194     const ContextMetadata& metadata() const { return metadata_; }
metadata()195     ContextMetadata& metadata() { return metadata_; }
schemeful_metadata()196     const ContextMetadata& schemeful_metadata() const {
197       return schemeful_metadata_;
198     }
schemeful_metadata()199     ContextMetadata& schemeful_metadata() { return schemeful_metadata_; }
200 
201     // Sets context types. Does not check for consistency between context and
202     // schemeful context. Does not touch the metadata.
203     void SetContextTypesForTesting(ContextType context_type,
204                                    ContextType schemeful_context_type);
205 
206     // Returns whether the context types and all fields of the metadata structs
207     // are the same.
208     bool CompleteEquivalenceForTesting(
209         const SameSiteCookieContext& other) const;
210 
211     // Equality operators disregard any metadata! (Only the context types are
212     // compared, not how they were computed.)
213     NET_EXPORT friend bool operator==(
214         const CookieOptions::SameSiteCookieContext& lhs,
215         const CookieOptions::SameSiteCookieContext& rhs);
216     NET_EXPORT friend bool operator!=(
217         const CookieOptions::SameSiteCookieContext& lhs,
218         const CookieOptions::SameSiteCookieContext& rhs);
219 
220    private:
221     ContextType context_;
222     ContextType schemeful_context_;
223 
224     ContextMetadata metadata_;
225     ContextMetadata schemeful_metadata_;
226   };
227 
228   // Creates a CookieOptions object which:
229   //
230   // * Excludes HttpOnly cookies
231   // * Excludes SameSite cookies
232   // * Updates last-accessed time.
233   // * Does not report excluded cookies in APIs that can do so.
234   // * Excludes SameParty cookies.
235   //
236   // These settings can be altered by calling:
237   //
238   // * |set_{include,exclude}_httponly()|
239   // * |set_same_site_cookie_context()|
240   // * |set_do_not_update_access_time()|
241   // * |set_same_party_cookie_context_type()|
242   CookieOptions();
243   CookieOptions(const CookieOptions& other);
244   CookieOptions(CookieOptions&& other);
245   ~CookieOptions();
246 
247   CookieOptions& operator=(const CookieOptions&);
248   CookieOptions& operator=(CookieOptions&&);
249 
set_exclude_httponly()250   void set_exclude_httponly() { exclude_httponly_ = true; }
set_include_httponly()251   void set_include_httponly() { exclude_httponly_ = false; }
exclude_httponly()252   bool exclude_httponly() const { return exclude_httponly_; }
253 
254   // How trusted is the current browser environment when it comes to accessing
255   // SameSite cookies. Default is not trusted, e.g. CROSS_SITE.
set_same_site_cookie_context(const SameSiteCookieContext & context)256   void set_same_site_cookie_context(const SameSiteCookieContext& context) {
257     same_site_cookie_context_ = context;
258   }
259 
same_site_cookie_context()260   const SameSiteCookieContext& same_site_cookie_context() const {
261     return same_site_cookie_context_;
262   }
263 
set_update_access_time()264   void set_update_access_time() { update_access_time_ = true; }
set_do_not_update_access_time()265   void set_do_not_update_access_time() { update_access_time_ = false; }
update_access_time()266   bool update_access_time() const { return update_access_time_; }
267 
set_return_excluded_cookies()268   void set_return_excluded_cookies() { return_excluded_cookies_ = true; }
unset_return_excluded_cookies()269   void unset_return_excluded_cookies() { return_excluded_cookies_ = false; }
return_excluded_cookies()270   bool return_excluded_cookies() const { return return_excluded_cookies_; }
271 
set_same_party_context(const SamePartyContext & context)272   void set_same_party_context(const SamePartyContext& context) {
273     same_party_context_ = context;
274   }
same_party_context()275   const SamePartyContext& same_party_context() const {
276     return same_party_context_;
277   }
278 
279   // Getter/setter of |full_party_context_size_| for logging purposes.
set_full_party_context_size(uint32_t len)280   void set_full_party_context_size(uint32_t len) {
281     full_party_context_size_ = len;
282   }
full_party_context_size()283   uint32_t full_party_context_size() const { return full_party_context_size_; }
284 
set_is_in_nontrivial_first_party_set(bool is_member)285   void set_is_in_nontrivial_first_party_set(bool is_member) {
286     is_in_nontrivial_first_party_set_ = is_member;
287   }
is_in_nontrivial_first_party_set()288   bool is_in_nontrivial_first_party_set() const {
289     return is_in_nontrivial_first_party_set_;
290   }
291 
292   // Convenience method for where you need a CookieOptions that will
293   // work for getting/setting all types of cookies, including HttpOnly and
294   // SameSite cookies. Also specifies not to update the access time, because
295   // usually this is done to get all the cookies to check that they are correct,
296   // including the creation time. This basically makes a CookieOptions that is
297   // the opposite of the default CookieOptions.
298   static CookieOptions MakeAllInclusive();
299 
300  private:
301   // Keep default values in sync with
302   // content/public/common/cookie_manager.mojom.
303   bool exclude_httponly_ = true;
304   SameSiteCookieContext same_site_cookie_context_;
305   bool update_access_time_ = true;
306   bool return_excluded_cookies_ = false;
307 
308   SamePartyContext same_party_context_;
309 
310   // The size of the isolation_info.party_context plus the top-frame site.
311   // Stored for logging purposes.
312   uint32_t full_party_context_size_ = 0;
313   // Whether the site requesting cookie access (as opposed to e.g. the
314   // `site_for_cookies`) is a member (or owner) of a nontrivial First-Party
315   // Set.
316   // This is included here temporarily, for the purpose of ignoring SameParty
317   // for sites that are not participating in the Origin Trial.
318   // TODO(https://crbug.com/1163990): remove this field.
319   bool is_in_nontrivial_first_party_set_ = false;
320 };
321 
322 NET_EXPORT bool operator==(
323     const CookieOptions::SameSiteCookieContext::ContextMetadata& lhs,
324     const CookieOptions::SameSiteCookieContext::ContextMetadata& rhs);
325 NET_EXPORT bool operator!=(
326     const CookieOptions::SameSiteCookieContext::ContextMetadata& lhs,
327     const CookieOptions::SameSiteCookieContext::ContextMetadata& rhs);
328 
329 // Allows gtest to print more helpful error messages instead of printing hex.
330 // (No need to null-check `os` because we can assume gtest will properly pass a
331 // non-null pointer, and it is dereferenced immediately anyway.)
PrintTo(CookieOptions::SameSiteCookieContext::ContextType ct,std::ostream * os)332 inline void PrintTo(CookieOptions::SameSiteCookieContext::ContextType ct,
333                     std::ostream* os) {
334   *os << static_cast<int>(ct);
335 }
336 
PrintTo(const CookieOptions::SameSiteCookieContext::ContextMetadata & m,std::ostream * os)337 inline void PrintTo(
338     const CookieOptions::SameSiteCookieContext::ContextMetadata& m,
339     std::ostream* os) {
340   *os << "{";
341   *os << " cross_site_redirect_downgrade: "
342       << static_cast<int>(m.cross_site_redirect_downgrade);
343   *os << ", redirect_type_bug_1221316: "
344       << static_cast<int>(m.redirect_type_bug_1221316);
345   *os << ", http_method_bug_1221316: "
346       << static_cast<int>(m.http_method_bug_1221316);
347   *os << " }";
348 }
349 
PrintTo(const CookieOptions::SameSiteCookieContext & sscc,std::ostream * os)350 inline void PrintTo(const CookieOptions::SameSiteCookieContext& sscc,
351                     std::ostream* os) {
352   *os << "{ context: ";
353   PrintTo(sscc.context(), os);
354   *os << ", schemeful_context: ";
355   PrintTo(sscc.schemeful_context(), os);
356   *os << ", metadata: ";
357   PrintTo(sscc.metadata(), os);
358   *os << ", schemeful_metadata: ";
359   PrintTo(sscc.schemeful_metadata(), os);
360   *os << " }";
361 }
362 
363 }  // namespace net
364 
365 #endif  // NET_COOKIES_COOKIE_OPTIONS_H_
366