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