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