xref: /aosp_15_r20/external/cronet/net/cookies/parsed_cookie.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef NET_COOKIES_PARSED_COOKIE_H_
6*6777b538SAndroid Build Coastguard Worker #define NET_COOKIES_PARSED_COOKIE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <string>
11*6777b538SAndroid Build Coastguard Worker #include <utility>
12*6777b538SAndroid Build Coastguard Worker #include <vector>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_constants.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker namespace net {
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker class CookieInclusionStatus;
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker class NET_EXPORT ParsedCookie {
22*6777b538SAndroid Build Coastguard Worker  public:
23*6777b538SAndroid Build Coastguard Worker   typedef std::pair<std::string, std::string> TokenValuePair;
24*6777b538SAndroid Build Coastguard Worker   typedef std::vector<TokenValuePair> PairList;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker   // The maximum length allowed for a cookie string's name/value pair.
27*6777b538SAndroid Build Coastguard Worker   static const size_t kMaxCookieNamePlusValueSize = 4096;
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker   // The maximum length allowed for each attribute value in a cookie string.
30*6777b538SAndroid Build Coastguard Worker   static const size_t kMaxCookieAttributeValueSize = 1024;
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker   // Construct from a cookie string like "BLAH=1; path=/; domain=.google.com"
33*6777b538SAndroid Build Coastguard Worker   // Format is according to RFC6265bis. Cookies with both name and value empty
34*6777b538SAndroid Build Coastguard Worker   // will be considered invalid.
35*6777b538SAndroid Build Coastguard Worker   // `status_out` is a nullable output param which will be populated with
36*6777b538SAndroid Build Coastguard Worker   // informative exclusion reasons if the resulting ParsedCookie is invalid.
37*6777b538SAndroid Build Coastguard Worker   // The CookieInclusionStatus will not be altered if the resulting ParsedCookie
38*6777b538SAndroid Build Coastguard Worker   // is valid.
39*6777b538SAndroid Build Coastguard Worker   // `block_truncated` indicates whether cookies containing '\00', '\r', or '\n'
40*6777b538SAndroid Build Coastguard Worker   // characters should be treated as invalid.
41*6777b538SAndroid Build Coastguard Worker   explicit ParsedCookie(const std::string& cookie_line,
42*6777b538SAndroid Build Coastguard Worker                         bool block_truncated = true,
43*6777b538SAndroid Build Coastguard Worker                         CookieInclusionStatus* status_out = nullptr);
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   ParsedCookie(const ParsedCookie&) = delete;
46*6777b538SAndroid Build Coastguard Worker   ParsedCookie& operator=(const ParsedCookie&) = delete;
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker   ~ParsedCookie();
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker   // You should not call any other methods except for SetName/SetValue on the
51*6777b538SAndroid Build Coastguard Worker   // class if !IsValid.
52*6777b538SAndroid Build Coastguard Worker   bool IsValid() const;
53*6777b538SAndroid Build Coastguard Worker 
Name()54*6777b538SAndroid Build Coastguard Worker   const std::string& Name() const { return pairs_[0].first; }
Token()55*6777b538SAndroid Build Coastguard Worker   const std::string& Token() const { return Name(); }
Value()56*6777b538SAndroid Build Coastguard Worker   const std::string& Value() const { return pairs_[0].second; }
57*6777b538SAndroid Build Coastguard Worker 
HasPath()58*6777b538SAndroid Build Coastguard Worker   bool HasPath() const { return path_index_ != 0; }
Path()59*6777b538SAndroid Build Coastguard Worker   const std::string& Path() const {
60*6777b538SAndroid Build Coastguard Worker     DCHECK(HasPath());
61*6777b538SAndroid Build Coastguard Worker     return pairs_[path_index_].second;
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker   // Note that Domain() may return the empty string; in the case of cookie_line
64*6777b538SAndroid Build Coastguard Worker   // "domain=", HasDomain() will return true (as the empty string is an
65*6777b538SAndroid Build Coastguard Worker   // acceptable domain value), so Domain() will return std::string().
HasDomain()66*6777b538SAndroid Build Coastguard Worker   bool HasDomain() const { return domain_index_ != 0; }
Domain()67*6777b538SAndroid Build Coastguard Worker   const std::string& Domain() const {
68*6777b538SAndroid Build Coastguard Worker     DCHECK(HasDomain());
69*6777b538SAndroid Build Coastguard Worker     return pairs_[domain_index_].second;
70*6777b538SAndroid Build Coastguard Worker   }
HasExpires()71*6777b538SAndroid Build Coastguard Worker   bool HasExpires() const { return expires_index_ != 0; }
Expires()72*6777b538SAndroid Build Coastguard Worker   const std::string& Expires() const {
73*6777b538SAndroid Build Coastguard Worker     DCHECK(HasExpires());
74*6777b538SAndroid Build Coastguard Worker     return pairs_[expires_index_].second;
75*6777b538SAndroid Build Coastguard Worker   }
HasMaxAge()76*6777b538SAndroid Build Coastguard Worker   bool HasMaxAge() const { return maxage_index_ != 0; }
MaxAge()77*6777b538SAndroid Build Coastguard Worker   const std::string& MaxAge() const {
78*6777b538SAndroid Build Coastguard Worker     DCHECK(HasMaxAge());
79*6777b538SAndroid Build Coastguard Worker     return pairs_[maxage_index_].second;
80*6777b538SAndroid Build Coastguard Worker   }
IsSecure()81*6777b538SAndroid Build Coastguard Worker   bool IsSecure() const { return secure_index_ != 0; }
IsHttpOnly()82*6777b538SAndroid Build Coastguard Worker   bool IsHttpOnly() const { return httponly_index_ != 0; }
83*6777b538SAndroid Build Coastguard Worker   // Also spits out an enum value representing the string given as the SameSite
84*6777b538SAndroid Build Coastguard Worker   // attribute value, if |samesite_string| is non-null.
85*6777b538SAndroid Build Coastguard Worker   CookieSameSite SameSite(
86*6777b538SAndroid Build Coastguard Worker       CookieSameSiteString* samesite_string = nullptr) const;
87*6777b538SAndroid Build Coastguard Worker   CookiePriority Priority() const;
IsPartitioned()88*6777b538SAndroid Build Coastguard Worker   bool IsPartitioned() const { return partitioned_index_ != 0; }
HasInternalHtab()89*6777b538SAndroid Build Coastguard Worker   bool HasInternalHtab() const { return internal_htab_; }
90*6777b538SAndroid Build Coastguard Worker   TruncatingCharacterInCookieStringType
GetTruncatingCharacterInCookieStringType()91*6777b538SAndroid Build Coastguard Worker   GetTruncatingCharacterInCookieStringType() const {
92*6777b538SAndroid Build Coastguard Worker     return truncating_char_in_cookie_string_type_;
93*6777b538SAndroid Build Coastguard Worker   }
94*6777b538SAndroid Build Coastguard Worker   // Returns the number of attributes, for example, returning 2 for:
95*6777b538SAndroid Build Coastguard Worker   //   "BLAH=hah; path=/; domain=.google.com"
NumberOfAttributes()96*6777b538SAndroid Build Coastguard Worker   size_t NumberOfAttributes() const { return pairs_.size() - 1; }
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   // These functions set the respective properties of the cookie. If the
99*6777b538SAndroid Build Coastguard Worker   // parameters are empty, the respective properties are cleared.
100*6777b538SAndroid Build Coastguard Worker   // The functions return false in case an error occurred.
101*6777b538SAndroid Build Coastguard Worker   // The cookie needs to be assigned a name/value before setting the other
102*6777b538SAndroid Build Coastguard Worker   // attributes.
103*6777b538SAndroid Build Coastguard Worker   //
104*6777b538SAndroid Build Coastguard Worker   // These functions should only be used if you need to modify a response's
105*6777b538SAndroid Build Coastguard Worker   // Set-Cookie string. The resulting ParsedCookie and its Set-Cookie string
106*6777b538SAndroid Build Coastguard Worker   // should still go through the regular cookie parsing process before entering
107*6777b538SAndroid Build Coastguard Worker   // the cookie jar.
108*6777b538SAndroid Build Coastguard Worker   bool SetName(const std::string& name);
109*6777b538SAndroid Build Coastguard Worker   bool SetValue(const std::string& value);
110*6777b538SAndroid Build Coastguard Worker   bool SetPath(const std::string& path);
111*6777b538SAndroid Build Coastguard Worker   bool SetDomain(const std::string& domain);
112*6777b538SAndroid Build Coastguard Worker   bool SetExpires(const std::string& expires);
113*6777b538SAndroid Build Coastguard Worker   bool SetMaxAge(const std::string& maxage);
114*6777b538SAndroid Build Coastguard Worker   bool SetIsSecure(bool is_secure);
115*6777b538SAndroid Build Coastguard Worker   bool SetIsHttpOnly(bool is_http_only);
116*6777b538SAndroid Build Coastguard Worker   bool SetSameSite(const std::string& same_site);
117*6777b538SAndroid Build Coastguard Worker   bool SetPriority(const std::string& priority);
118*6777b538SAndroid Build Coastguard Worker   bool SetIsPartitioned(bool is_partitioned);
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   // Returns the cookie description as it appears in a HTML response header.
121*6777b538SAndroid Build Coastguard Worker   std::string ToCookieLine() const;
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   // Returns an iterator pointing to the first terminator character found in
124*6777b538SAndroid Build Coastguard Worker   // the given string.
125*6777b538SAndroid Build Coastguard Worker   static std::string::const_iterator FindFirstTerminator(const std::string& s);
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker   // Given iterators pointing to the beginning and end of a string segment,
128*6777b538SAndroid Build Coastguard Worker   // returns as output arguments token_start and token_end to the start and end
129*6777b538SAndroid Build Coastguard Worker   // positions of a cookie attribute token name parsed from the segment, and
130*6777b538SAndroid Build Coastguard Worker   // updates the segment iterator to point to the next segment to be parsed.
131*6777b538SAndroid Build Coastguard Worker   // If no token is found, the function returns false and the segment iterator
132*6777b538SAndroid Build Coastguard Worker   // is set to end.
133*6777b538SAndroid Build Coastguard Worker   static bool ParseToken(std::string::const_iterator* it,
134*6777b538SAndroid Build Coastguard Worker                          const std::string::const_iterator& end,
135*6777b538SAndroid Build Coastguard Worker                          std::string::const_iterator* token_start,
136*6777b538SAndroid Build Coastguard Worker                          std::string::const_iterator* token_end);
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   // Given iterators pointing to the beginning and end of a string segment,
139*6777b538SAndroid Build Coastguard Worker   // returns as output arguments value_start and value_end to the start and end
140*6777b538SAndroid Build Coastguard Worker   // positions of a cookie attribute value parsed from the segment, and updates
141*6777b538SAndroid Build Coastguard Worker   // the segment iterator to point to the next segment to be parsed.
142*6777b538SAndroid Build Coastguard Worker   static void ParseValue(std::string::const_iterator* it,
143*6777b538SAndroid Build Coastguard Worker                          const std::string::const_iterator& end,
144*6777b538SAndroid Build Coastguard Worker                          std::string::const_iterator* value_start,
145*6777b538SAndroid Build Coastguard Worker                          std::string::const_iterator* value_end);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // Same as the above functions, except the input is assumed to contain the
148*6777b538SAndroid Build Coastguard Worker   // desired token/value and nothing else.
149*6777b538SAndroid Build Coastguard Worker   static std::string ParseTokenString(const std::string& token);
150*6777b538SAndroid Build Coastguard Worker   static std::string ParseValueString(const std::string& value);
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   // Returns |true| if the parsed version of |value| matches |value|.
153*6777b538SAndroid Build Coastguard Worker   static bool ValueMatchesParsedValue(const std::string& value);
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker   // Is the string valid as the name of the cookie or as an attribute name?
156*6777b538SAndroid Build Coastguard Worker   static bool IsValidCookieName(const std::string& name);
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker   // Is the string valid as the value of the cookie?
159*6777b538SAndroid Build Coastguard Worker   static bool IsValidCookieValue(const std::string& value);
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   // Is the string free of any characters not allowed in attribute values?
162*6777b538SAndroid Build Coastguard Worker   static bool CookieAttributeValueHasValidCharSet(const std::string& value);
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Is the string less than the size limits set for attribute values?
165*6777b538SAndroid Build Coastguard Worker   static bool CookieAttributeValueHasValidSize(const std::string& value);
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   // Returns `true` if the name and value combination are valid. Calls
168*6777b538SAndroid Build Coastguard Worker   // IsValidCookieName() and IsValidCookieValue() on `name` and `value`
169*6777b538SAndroid Build Coastguard Worker   // respectively, in addition to checking that the sum of the two doesn't
170*6777b538SAndroid Build Coastguard Worker   // exceed size limits specified in RFC6265bis.
171*6777b538SAndroid Build Coastguard Worker   static bool IsValidCookieNameValuePair(
172*6777b538SAndroid Build Coastguard Worker       const std::string& name,
173*6777b538SAndroid Build Coastguard Worker       const std::string& value,
174*6777b538SAndroid Build Coastguard Worker       CookieInclusionStatus* status_out = nullptr);
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker  private:
177*6777b538SAndroid Build Coastguard Worker   void ParseTokenValuePairs(const std::string& cookie_line,
178*6777b538SAndroid Build Coastguard Worker                             bool block_truncated,
179*6777b538SAndroid Build Coastguard Worker                             CookieInclusionStatus& status_out);
180*6777b538SAndroid Build Coastguard Worker   void SetupAttributes();
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker   // Sets a key/value pair for a cookie. |index| has to point to one of the
183*6777b538SAndroid Build Coastguard Worker   // |*_index_| fields in ParsedCookie and is updated to the position where
184*6777b538SAndroid Build Coastguard Worker   // the key/value pair is set in |pairs_|. Accordingly, |key| has to correspond
185*6777b538SAndroid Build Coastguard Worker   // to the token matching |index|. If |value| contains invalid characters, the
186*6777b538SAndroid Build Coastguard Worker   // cookie parameter is not changed and the function returns false.
187*6777b538SAndroid Build Coastguard Worker   // If |value| is empty/false the key/value pair is removed.
188*6777b538SAndroid Build Coastguard Worker   bool SetString(size_t* index,
189*6777b538SAndroid Build Coastguard Worker                  const std::string& key,
190*6777b538SAndroid Build Coastguard Worker                  const std::string& value);
191*6777b538SAndroid Build Coastguard Worker   bool SetBool(size_t* index, const std::string& key, bool value);
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker   // Helper function for SetString and SetBool handling the case that the
194*6777b538SAndroid Build Coastguard Worker   // key/value pair shall not be removed.
195*6777b538SAndroid Build Coastguard Worker   bool SetAttributePair(size_t* index,
196*6777b538SAndroid Build Coastguard Worker                         const std::string& key,
197*6777b538SAndroid Build Coastguard Worker                         const std::string& value);
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker   // Removes the key/value pair from a cookie that is identified by |index|.
200*6777b538SAndroid Build Coastguard Worker   // |index| refers to a position in |pairs_|.
201*6777b538SAndroid Build Coastguard Worker   void ClearAttributePair(size_t index);
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker   PairList pairs_;
204*6777b538SAndroid Build Coastguard Worker   // These will default to 0, but that should never be valid since the
205*6777b538SAndroid Build Coastguard Worker   // 0th index is the user supplied cookie name/value, not an attribute.
206*6777b538SAndroid Build Coastguard Worker   size_t path_index_ = 0;
207*6777b538SAndroid Build Coastguard Worker   size_t domain_index_ = 0;
208*6777b538SAndroid Build Coastguard Worker   size_t expires_index_ = 0;
209*6777b538SAndroid Build Coastguard Worker   size_t maxage_index_ = 0;
210*6777b538SAndroid Build Coastguard Worker   size_t secure_index_ = 0;
211*6777b538SAndroid Build Coastguard Worker   size_t httponly_index_ = 0;
212*6777b538SAndroid Build Coastguard Worker   size_t same_site_index_ = 0;
213*6777b538SAndroid Build Coastguard Worker   size_t priority_index_ = 0;
214*6777b538SAndroid Build Coastguard Worker   size_t partitioned_index_ = 0;
215*6777b538SAndroid Build Coastguard Worker   TruncatingCharacterInCookieStringType truncating_char_in_cookie_string_type_ =
216*6777b538SAndroid Build Coastguard Worker       TruncatingCharacterInCookieStringType::kTruncatingCharNone;
217*6777b538SAndroid Build Coastguard Worker   // For metrics on cookie name/value internal HTABS
218*6777b538SAndroid Build Coastguard Worker   bool internal_htab_ = false;
219*6777b538SAndroid Build Coastguard Worker };
220*6777b538SAndroid Build Coastguard Worker 
221*6777b538SAndroid Build Coastguard Worker }  // namespace net
222*6777b538SAndroid Build Coastguard Worker 
223*6777b538SAndroid Build Coastguard Worker #endif  // NET_COOKIES_PARSED_COOKIE_H_
224