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