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