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