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