parsed_cookie_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <string> 6 7#include "net/cookies/parsed_cookie.h" 8#include "testing/gtest/include/gtest/gtest.h" 9 10namespace net { 11 12namespace { 13 14class ParsedCookieTest : public testing::Test { }; 15 16} // namespace 17 18TEST(ParsedCookieTest, TestBasic) { 19 ParsedCookie pc("a=b"); 20 EXPECT_TRUE(pc.IsValid()); 21 EXPECT_FALSE(pc.IsSecure()); 22 EXPECT_EQ("a", pc.Name()); 23 EXPECT_EQ("b", pc.Value()); 24} 25 26TEST(ParsedCookieTest, TestQuoted) { 27 // These are some quoting cases which the major browsers all 28 // handle differently. I've tested Internet Explorer 6, Opera 9.6, 29 // Firefox 3, and Safari Windows 3.2.1. We originally tried to match 30 // Firefox closely, however we now match Internet Explorer and Safari. 31 const char* values[] = { 32 // Trailing whitespace after a quoted value. The whitespace after 33 // the quote is stripped in all browsers. 34 "\"zzz \" ", "\"zzz \"", 35 // Handling a quoted value with a ';', like FOO="zz;pp" ; 36 // IE and Safari: "zz; 37 // Firefox and Opera: "zz;pp" 38 "\"zz;pp\" ;", "\"zz", 39 // Handling a value with multiple quoted parts, like FOO="zzz " "ppp" ; 40 // IE and Safari: "zzz " "ppp"; 41 // Firefox: "zzz "; 42 // Opera: <rejects cookie> 43 "\"zzz \" \"ppp\" ", "\"zzz \" \"ppp\"", 44 // A quote in a value that didn't start quoted. like FOO=A"B ; 45 // IE, Safari, and Firefox: A"B; 46 // Opera: <rejects cookie> 47 "A\"B", "A\"B", 48 }; 49 50 for (size_t i = 0; i < arraysize(values); i += 2) { 51 std::string input(values[i]); 52 std::string expected(values[i + 1]); 53 54 ParsedCookie pc("aBc=" + input + " ; path=\"/\" ; httponly "); 55 EXPECT_TRUE(pc.IsValid()); 56 EXPECT_FALSE(pc.IsSecure()); 57 EXPECT_TRUE(pc.IsHttpOnly()); 58 EXPECT_TRUE(pc.HasPath()); 59 EXPECT_EQ("aBc", pc.Name()); 60 EXPECT_EQ(expected, pc.Value()); 61 62 // If a path was quoted, the path attribute keeps the quotes. This will 63 // make the cookie effectively useless, but path parameters aren't supposed 64 // to be quoted. Bug 1261605. 65 EXPECT_EQ("\"/\"", pc.Path()); 66 } 67} 68 69TEST(ParsedCookieTest, TestNameless) { 70 ParsedCookie pc("BLAHHH; path=/; secure;"); 71 EXPECT_TRUE(pc.IsValid()); 72 EXPECT_TRUE(pc.IsSecure()); 73 EXPECT_TRUE(pc.HasPath()); 74 EXPECT_EQ("/", pc.Path()); 75 EXPECT_EQ("", pc.Name()); 76 EXPECT_EQ("BLAHHH", pc.Value()); 77} 78 79TEST(ParsedCookieTest, TestAttributeCase) { 80 ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY"); 81 EXPECT_TRUE(pc.IsValid()); 82 EXPECT_TRUE(pc.IsSecure()); 83 EXPECT_TRUE(pc.IsHttpOnly()); 84 EXPECT_TRUE(pc.HasPath()); 85 EXPECT_EQ("/", pc.Path()); 86 EXPECT_EQ("", pc.Name()); 87 EXPECT_EQ("BLAHHH", pc.Value()); 88 EXPECT_EQ(3U, pc.NumberOfAttributes()); 89} 90 91TEST(ParsedCookieTest, TestDoubleQuotedNameless) { 92 ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;"); 93 EXPECT_TRUE(pc.IsValid()); 94 EXPECT_TRUE(pc.IsSecure()); 95 EXPECT_TRUE(pc.HasPath()); 96 EXPECT_EQ("/", pc.Path()); 97 EXPECT_EQ("", pc.Name()); 98 EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value()); 99 EXPECT_EQ(2U, pc.NumberOfAttributes()); 100} 101 102TEST(ParsedCookieTest, QuoteOffTheEnd) { 103 ParsedCookie pc("a=\"B"); 104 EXPECT_TRUE(pc.IsValid()); 105 EXPECT_EQ("a", pc.Name()); 106 EXPECT_EQ("\"B", pc.Value()); 107 EXPECT_EQ(0U, pc.NumberOfAttributes()); 108} 109 110TEST(ParsedCookieTest, MissingName) { 111 ParsedCookie pc("=ABC"); 112 EXPECT_TRUE(pc.IsValid()); 113 EXPECT_EQ("", pc.Name()); 114 EXPECT_EQ("ABC", pc.Value()); 115 EXPECT_EQ(0U, pc.NumberOfAttributes()); 116} 117 118TEST(ParsedCookieTest, MissingValue) { 119 ParsedCookie pc("ABC=; path = /wee"); 120 EXPECT_TRUE(pc.IsValid()); 121 EXPECT_EQ("ABC", pc.Name()); 122 EXPECT_EQ("", pc.Value()); 123 EXPECT_TRUE(pc.HasPath()); 124 EXPECT_EQ("/wee", pc.Path()); 125 EXPECT_EQ(1U, pc.NumberOfAttributes()); 126} 127 128TEST(ParsedCookieTest, Whitespace) { 129 ParsedCookie pc(" A = BC ;secure;;; httponly"); 130 EXPECT_TRUE(pc.IsValid()); 131 EXPECT_EQ("A", pc.Name()); 132 EXPECT_EQ("BC", pc.Value()); 133 EXPECT_FALSE(pc.HasPath()); 134 EXPECT_FALSE(pc.HasDomain()); 135 EXPECT_TRUE(pc.IsSecure()); 136 EXPECT_TRUE(pc.IsHttpOnly()); 137 // We parse anything between ; as attributes, so we end up with two 138 // attributes with an empty string name and value. 139 EXPECT_EQ(4U, pc.NumberOfAttributes()); 140} 141TEST(ParsedCookieTest, MultipleEquals) { 142 ParsedCookie pc(" A=== BC ;secure;;; httponly"); 143 EXPECT_TRUE(pc.IsValid()); 144 EXPECT_EQ("A", pc.Name()); 145 EXPECT_EQ("== BC", pc.Value()); 146 EXPECT_FALSE(pc.HasPath()); 147 EXPECT_FALSE(pc.HasDomain()); 148 EXPECT_TRUE(pc.IsSecure()); 149 EXPECT_TRUE(pc.IsHttpOnly()); 150 EXPECT_EQ(4U, pc.NumberOfAttributes()); 151} 152 153TEST(ParsedCookieTest, QuotedTrailingWhitespace) { 154 ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\" ; " 155 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " 156 "path=/ ; "); 157 EXPECT_TRUE(pc.IsValid()); 158 EXPECT_EQ("ANCUUID", pc.Name()); 159 // Stripping whitespace after the quotes matches all other major browsers. 160 EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value()); 161 EXPECT_TRUE(pc.HasExpires()); 162 EXPECT_TRUE(pc.HasPath()); 163 EXPECT_EQ("/", pc.Path()); 164 EXPECT_EQ(2U, pc.NumberOfAttributes()); 165} 166 167TEST(ParsedCookieTest, TrailingWhitespace) { 168 ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; " 169 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " 170 "path=/ ; "); 171 EXPECT_TRUE(pc.IsValid()); 172 EXPECT_EQ("ANCUUID", pc.Name()); 173 EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value()); 174 EXPECT_TRUE(pc.HasExpires()); 175 EXPECT_TRUE(pc.HasPath()); 176 EXPECT_EQ("/", pc.Path()); 177 EXPECT_EQ(2U, pc.NumberOfAttributes()); 178} 179 180TEST(ParsedCookieTest, TooManyPairs) { 181 std::string blankpairs; 182 blankpairs.resize(ParsedCookie::kMaxPairs - 1, ';'); 183 184 ParsedCookie pc1(blankpairs + "secure"); 185 EXPECT_TRUE(pc1.IsValid()); 186 EXPECT_TRUE(pc1.IsSecure()); 187 188 ParsedCookie pc2(blankpairs + ";secure"); 189 EXPECT_TRUE(pc2.IsValid()); 190 EXPECT_FALSE(pc2.IsSecure()); 191} 192 193// TODO(erikwright): some better test cases for invalid cookies. 194TEST(ParsedCookieTest, InvalidWhitespace) { 195 ParsedCookie pc(" "); 196 EXPECT_FALSE(pc.IsValid()); 197} 198 199TEST(ParsedCookieTest, InvalidTooLong) { 200 std::string maxstr; 201 maxstr.resize(ParsedCookie::kMaxCookieSize, 'a'); 202 203 ParsedCookie pc1(maxstr); 204 EXPECT_TRUE(pc1.IsValid()); 205 206 ParsedCookie pc2(maxstr + "A"); 207 EXPECT_FALSE(pc2.IsValid()); 208} 209 210TEST(ParsedCookieTest, InvalidEmpty) { 211 ParsedCookie pc(""); 212 EXPECT_FALSE(pc.IsValid()); 213} 214 215TEST(ParsedCookieTest, EmbeddedTerminator) { 216 ParsedCookie pc1("AAA=BB\0ZYX"); 217 ParsedCookie pc2("AAA=BB\rZYX"); 218 ParsedCookie pc3("AAA=BB\nZYX"); 219 EXPECT_TRUE(pc1.IsValid()); 220 EXPECT_EQ("AAA", pc1.Name()); 221 EXPECT_EQ("BB", pc1.Value()); 222 EXPECT_TRUE(pc2.IsValid()); 223 EXPECT_EQ("AAA", pc2.Name()); 224 EXPECT_EQ("BB", pc2.Value()); 225 EXPECT_TRUE(pc3.IsValid()); 226 EXPECT_EQ("AAA", pc3.Name()); 227 EXPECT_EQ("BB", pc3.Value()); 228} 229 230TEST(ParsedCookieTest, ParseTokensAndValues) { 231 EXPECT_EQ("hello", 232 ParsedCookie::ParseTokenString("hello\nworld")); 233 EXPECT_EQ("fs!!@", 234 ParsedCookie::ParseTokenString("fs!!@;helloworld")); 235 EXPECT_EQ("hello world\tgood", 236 ParsedCookie::ParseTokenString("hello world\tgood\rbye")); 237 EXPECT_EQ("A", 238 ParsedCookie::ParseTokenString("A=B=C;D=E")); 239 EXPECT_EQ("hello", 240 ParsedCookie::ParseValueString("hello\nworld")); 241 EXPECT_EQ("fs!!@", 242 ParsedCookie::ParseValueString("fs!!@;helloworld")); 243 EXPECT_EQ("hello world\tgood", 244 ParsedCookie::ParseValueString("hello world\tgood\rbye")); 245 EXPECT_EQ("A=B=C", 246 ParsedCookie::ParseValueString("A=B=C;D=E")); 247} 248 249TEST(ParsedCookieTest, SerializeCookieLine) { 250 const char input[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; " 251 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " 252 "path=/ ; "; 253 const char output[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D; " 254 "expires=Sun, 18-Apr-2027 21:06:29 GMT; " 255 "path=/"; 256 ParsedCookie pc(input); 257 EXPECT_EQ(output, pc.ToCookieLine()); 258} 259 260 261TEST(ParsedCookieTest, SetNameAndValue) { 262 ParsedCookie empty(""); 263 EXPECT_FALSE(empty.IsValid()); 264 EXPECT_FALSE(empty.SetDomain("foobar.com")); 265 EXPECT_TRUE(empty.SetName("name")); 266 EXPECT_TRUE(empty.SetValue("value")); 267 EXPECT_EQ("name=value", empty.ToCookieLine()); 268 EXPECT_TRUE(empty.IsValid()); 269 270 // We don't test 271 // ParsedCookie invalid("@foo=bar"); 272 // EXPECT_FALSE(invalid.IsValid()); 273 // here because we are slightly more tolerant to invalid cookie names and 274 // values that are set by webservers. We only enforce a correct name and 275 // value if set via SetName() and SetValue(). 276 277 ParsedCookie pc("name=value"); 278 EXPECT_TRUE(pc.IsValid()); 279 280 // Set invalid name / value. 281 EXPECT_FALSE(pc.SetName("@foobar")); 282 EXPECT_EQ("name=value", pc.ToCookieLine()); 283 EXPECT_TRUE(pc.IsValid()); 284 285 EXPECT_FALSE(pc.SetName("")); 286 EXPECT_EQ("name=value", pc.ToCookieLine()); 287 EXPECT_TRUE(pc.IsValid()); 288 289 EXPECT_FALSE(pc.SetValue("foo bar")); 290 EXPECT_EQ("name=value", pc.ToCookieLine()); 291 EXPECT_TRUE(pc.IsValid()); 292 293 EXPECT_FALSE(pc.SetValue("\"foobar")); 294 EXPECT_EQ("name=value", pc.ToCookieLine()); 295 EXPECT_TRUE(pc.IsValid()); 296 297 // Set valid name / value 298 EXPECT_TRUE(pc.SetName("test")); 299 EXPECT_EQ("test=value", pc.ToCookieLine()); 300 EXPECT_TRUE(pc.IsValid()); 301 302 EXPECT_TRUE(pc.SetValue("\"foobar\"")); 303 EXPECT_EQ("test=\"foobar\"", pc.ToCookieLine()); 304 EXPECT_TRUE(pc.IsValid()); 305 306 EXPECT_TRUE(pc.SetValue("")); 307 EXPECT_EQ("test=", pc.ToCookieLine()); 308 EXPECT_TRUE(pc.IsValid()); 309} 310 311TEST(ParsedCookieTest, SetAttributes) { 312 ParsedCookie pc("name=value"); 313 EXPECT_TRUE(pc.IsValid()); 314 315 // Clear an unset attribute. 316 EXPECT_TRUE(pc.SetDomain("")); 317 EXPECT_FALSE(pc.HasDomain()); 318 EXPECT_EQ("name=value", pc.ToCookieLine()); 319 EXPECT_TRUE(pc.IsValid()); 320 321 // Set a string containing an invalid character 322 EXPECT_FALSE(pc.SetDomain("foo;bar")); 323 EXPECT_FALSE(pc.HasDomain()); 324 EXPECT_EQ("name=value", pc.ToCookieLine()); 325 EXPECT_TRUE(pc.IsValid()); 326 327 // Set all other attributes and check that they are appended in order. 328 EXPECT_TRUE(pc.SetDomain("domain.com")); 329 EXPECT_TRUE(pc.SetPath("/")); 330 EXPECT_TRUE(pc.SetExpires("Sun, 18-Apr-2027 21:06:29 GMT")); 331 EXPECT_TRUE(pc.SetMaxAge("12345")); 332 EXPECT_TRUE(pc.SetIsSecure(true)); 333 EXPECT_TRUE(pc.SetIsHttpOnly(true)); 334 EXPECT_EQ("name=value; domain=domain.com; path=/; " 335 "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; " 336 "httponly", 337 pc.ToCookieLine()); 338 EXPECT_TRUE(pc.HasDomain()); 339 EXPECT_TRUE(pc.HasPath()); 340 EXPECT_TRUE(pc.HasExpires()); 341 EXPECT_TRUE(pc.HasMaxAge()); 342 EXPECT_TRUE(pc.IsSecure()); 343 EXPECT_TRUE(pc.IsHttpOnly()); 344 345 // Clear one attribute from the middle. 346 EXPECT_TRUE(pc.SetPath("/foo")); 347 EXPECT_TRUE(pc.HasDomain()); 348 EXPECT_TRUE(pc.HasPath()); 349 EXPECT_TRUE(pc.HasExpires()); 350 EXPECT_TRUE(pc.IsSecure()); 351 EXPECT_TRUE(pc.IsHttpOnly()); 352 EXPECT_EQ("name=value; domain=domain.com; path=/foo; " 353 "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; " 354 "httponly", 355 pc.ToCookieLine()); 356 357 // Clear the rest and change the name and value. 358 EXPECT_TRUE(pc.SetDomain("")); 359 EXPECT_TRUE(pc.SetPath("")); 360 EXPECT_TRUE(pc.SetExpires("")); 361 EXPECT_TRUE(pc.SetMaxAge("")); 362 EXPECT_TRUE(pc.SetIsSecure(false)); 363 EXPECT_TRUE(pc.SetIsHttpOnly(false)); 364 EXPECT_TRUE(pc.SetName("name2")); 365 EXPECT_TRUE(pc.SetValue("value2")); 366 EXPECT_FALSE(pc.HasDomain()); 367 EXPECT_FALSE(pc.HasPath()); 368 EXPECT_FALSE(pc.HasExpires()); 369 EXPECT_FALSE(pc.HasMaxAge()); 370 EXPECT_FALSE(pc.IsSecure()); 371 EXPECT_FALSE(pc.IsHttpOnly()); 372 EXPECT_EQ("name2=value2", pc.ToCookieLine()); 373} 374 375} // namespace net 376