root/net/cookies/parsed_cookie_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TEST
  2. TEST
  3. TEST
  4. TEST
  5. TEST
  6. TEST
  7. TEST
  8. TEST
  9. TEST
  10. TEST
  11. TEST
  12. TEST
  13. TEST
  14. TEST
  15. TEST
  16. TEST
  17. TEST
  18. TEST
  19. TEST
  20. TEST
  21. TEST
  22. TEST
  23. TEST
  24. TEST

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "net/cookies/cookie_constants.h"
#include "net/cookies/parsed_cookie.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

TEST(ParsedCookieTest, TestBasic) {
  ParsedCookie pc("a=b");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_FALSE(pc.IsSecure());
  EXPECT_EQ("a", pc.Name());
  EXPECT_EQ("b", pc.Value());
}

TEST(ParsedCookieTest, TestQuoted) {
  // These are some quoting cases which the major browsers all
  // handle differently.  I've tested Internet Explorer 6, Opera 9.6,
  // Firefox 3, and Safari Windows 3.2.1.  We originally tried to match
  // Firefox closely, however we now match Internet Explorer and Safari.
  const char* values[] = {
    // Trailing whitespace after a quoted value.  The whitespace after
    // the quote is stripped in all browsers.
    "\"zzz \"  ",              "\"zzz \"",
    // Handling a quoted value with a ';', like FOO="zz;pp"  ;
    // IE and Safari: "zz;
    // Firefox and Opera: "zz;pp"
    "\"zz;pp\" ;",             "\"zz",
    // Handling a value with multiple quoted parts, like FOO="zzz "   "ppp" ;
    // IE and Safari: "zzz "   "ppp";
    // Firefox: "zzz ";
    // Opera: <rejects cookie>
    "\"zzz \"   \"ppp\" ",     "\"zzz \"   \"ppp\"",
    // A quote in a value that didn't start quoted.  like FOO=A"B ;
    // IE, Safari, and Firefox: A"B;
    // Opera: <rejects cookie>
    "A\"B",                    "A\"B",
  };

  for (size_t i = 0; i < arraysize(values); i += 2) {
    std::string input(values[i]);
    std::string expected(values[i + 1]);

    ParsedCookie pc("aBc=" + input + " ; path=\"/\"  ; httponly ");
    EXPECT_TRUE(pc.IsValid());
    EXPECT_FALSE(pc.IsSecure());
    EXPECT_TRUE(pc.IsHttpOnly());
    EXPECT_TRUE(pc.HasPath());
    EXPECT_EQ("aBc", pc.Name());
    EXPECT_EQ(expected, pc.Value());

    // If a path was quoted, the path attribute keeps the quotes.  This will
    // make the cookie effectively useless, but path parameters aren't supposed
    // to be quoted.  Bug 1261605.
    EXPECT_EQ("\"/\"", pc.Path());
  }
}

TEST(ParsedCookieTest, TestNameless) {
  ParsedCookie pc("BLAHHH; path=/; secure;");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/", pc.Path());
  EXPECT_EQ("", pc.Name());
  EXPECT_EQ("BLAHHH", pc.Value());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
}

TEST(ParsedCookieTest, TestAttributeCase) {
  ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY; pRIoRitY=hIgH");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.IsHttpOnly());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/", pc.Path());
  EXPECT_EQ("", pc.Name());
  EXPECT_EQ("BLAHHH", pc.Value());
  EXPECT_EQ(COOKIE_PRIORITY_HIGH, pc.Priority());
  EXPECT_EQ(4U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, TestDoubleQuotedNameless) {
  ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/", pc.Path());
  EXPECT_EQ("", pc.Name());
  EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(2U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, QuoteOffTheEnd) {
  ParsedCookie pc("a=\"B");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("a", pc.Name());
  EXPECT_EQ("\"B", pc.Value());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(0U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, MissingName) {
  ParsedCookie pc("=ABC");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("", pc.Name());
  EXPECT_EQ("ABC", pc.Value());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(0U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, MissingValue) {
  ParsedCookie pc("ABC=;  path = /wee");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("ABC", pc.Name());
  EXPECT_EQ("", pc.Value());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/wee", pc.Path());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(1U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, Whitespace) {
  ParsedCookie pc("  A  = BC  ;secure;;;   httponly");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("A", pc.Name());
  EXPECT_EQ("BC", pc.Value());
  EXPECT_FALSE(pc.HasPath());
  EXPECT_FALSE(pc.HasDomain());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.IsHttpOnly());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  // We parse anything between ; as attributes, so we end up with two
  // attributes with an empty string name and value.
  EXPECT_EQ(4U, pc.NumberOfAttributes());
}
TEST(ParsedCookieTest, MultipleEquals) {
  ParsedCookie pc("  A=== BC  ;secure;;;   httponly");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("A", pc.Name());
  EXPECT_EQ("== BC", pc.Value());
  EXPECT_FALSE(pc.HasPath());
  EXPECT_FALSE(pc.HasDomain());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.IsHttpOnly());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(4U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, QuotedTrailingWhitespace) {
  ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\"  ; "
                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
                      "path=/  ;  ");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("ANCUUID", pc.Name());
  // Stripping whitespace after the quotes matches all other major browsers.
  EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value());
  EXPECT_TRUE(pc.HasExpires());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/", pc.Path());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(2U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, TrailingWhitespace) {
  ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D  ; "
                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
                      "path=/  ;  ");
  EXPECT_TRUE(pc.IsValid());
  EXPECT_EQ("ANCUUID", pc.Name());
  EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value());
  EXPECT_TRUE(pc.HasExpires());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_EQ("/", pc.Path());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
  EXPECT_EQ(2U, pc.NumberOfAttributes());
}

TEST(ParsedCookieTest, TooManyPairs) {
  std::string blankpairs;
  blankpairs.resize(ParsedCookie::kMaxPairs - 1, ';');

  ParsedCookie pc1(blankpairs + "secure");
  EXPECT_TRUE(pc1.IsValid());
  EXPECT_TRUE(pc1.IsSecure());

  ParsedCookie pc2(blankpairs + ";secure");
  EXPECT_TRUE(pc2.IsValid());
  EXPECT_FALSE(pc2.IsSecure());
}

// TODO(erikwright): some better test cases for invalid cookies.
TEST(ParsedCookieTest, InvalidWhitespace) {
  ParsedCookie pc("    ");
  EXPECT_FALSE(pc.IsValid());
}

TEST(ParsedCookieTest, InvalidTooLong) {
  std::string maxstr;
  maxstr.resize(ParsedCookie::kMaxCookieSize, 'a');

  ParsedCookie pc1(maxstr);
  EXPECT_TRUE(pc1.IsValid());

  ParsedCookie pc2(maxstr + "A");
  EXPECT_FALSE(pc2.IsValid());
}

TEST(ParsedCookieTest, InvalidEmpty) {
  ParsedCookie pc((std::string()));
  EXPECT_FALSE(pc.IsValid());
}

TEST(ParsedCookieTest, EmbeddedTerminator) {
  ParsedCookie pc1("AAA=BB\0ZYX");
  ParsedCookie pc2("AAA=BB\rZYX");
  ParsedCookie pc3("AAA=BB\nZYX");
  EXPECT_TRUE(pc1.IsValid());
  EXPECT_EQ("AAA", pc1.Name());
  EXPECT_EQ("BB", pc1.Value());
  EXPECT_TRUE(pc2.IsValid());
  EXPECT_EQ("AAA", pc2.Name());
  EXPECT_EQ("BB", pc2.Value());
  EXPECT_TRUE(pc3.IsValid());
  EXPECT_EQ("AAA", pc3.Name());
  EXPECT_EQ("BB", pc3.Value());
}

TEST(ParsedCookieTest, ParseTokensAndValues) {
  EXPECT_EQ("hello",
            ParsedCookie::ParseTokenString("hello\nworld"));
  EXPECT_EQ("fs!!@",
            ParsedCookie::ParseTokenString("fs!!@;helloworld"));
  EXPECT_EQ("hello world\tgood",
            ParsedCookie::ParseTokenString("hello world\tgood\rbye"));
  EXPECT_EQ("A",
            ParsedCookie::ParseTokenString("A=B=C;D=E"));
  EXPECT_EQ("hello",
            ParsedCookie::ParseValueString("hello\nworld"));
  EXPECT_EQ("fs!!@",
            ParsedCookie::ParseValueString("fs!!@;helloworld"));
  EXPECT_EQ("hello world\tgood",
            ParsedCookie::ParseValueString("hello world\tgood\rbye"));
  EXPECT_EQ("A=B=C",
            ParsedCookie::ParseValueString("A=B=C;D=E"));
}

TEST(ParsedCookieTest, SerializeCookieLine) {
  const char input[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D  ; "
                       "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
                       "path=/  ;  priority=low  ;  ";
  const char output[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D; "
                        "expires=Sun, 18-Apr-2027 21:06:29 GMT; "
                        "path=/; priority=low";
  ParsedCookie pc(input);
  EXPECT_EQ(output, pc.ToCookieLine());
}


TEST(ParsedCookieTest, SetNameAndValue) {
  ParsedCookie empty((std::string()));
  EXPECT_FALSE(empty.IsValid());
  EXPECT_FALSE(empty.SetDomain("foobar.com"));
  EXPECT_TRUE(empty.SetName("name"));
  EXPECT_TRUE(empty.SetValue("value"));
  EXPECT_EQ("name=value", empty.ToCookieLine());
  EXPECT_TRUE(empty.IsValid());

  // We don't test
  //   ParsedCookie invalid("@foo=bar");
  //   EXPECT_FALSE(invalid.IsValid());
  // here because we are slightly more tolerant to invalid cookie names and
  // values that are set by webservers. We only enforce a correct name and
  // value if set via SetName() and SetValue().

  ParsedCookie pc("name=value");
  EXPECT_TRUE(pc.IsValid());

  // Set invalid name / value.
  EXPECT_FALSE(pc.SetName("@foobar"));
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  EXPECT_FALSE(pc.SetName(std::string()));
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  EXPECT_FALSE(pc.SetValue("foo bar"));
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  EXPECT_FALSE(pc.SetValue("\"foobar"));
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  // Set valid name / value
  EXPECT_TRUE(pc.SetName("test"));
  EXPECT_EQ("test=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  EXPECT_TRUE(pc.SetValue("\"foobar\""));
  EXPECT_EQ("test=\"foobar\"", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  EXPECT_TRUE(pc.SetValue(std::string()));
  EXPECT_EQ("test=", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());
}

TEST(ParsedCookieTest, SetAttributes) {
  ParsedCookie pc("name=value");
  EXPECT_TRUE(pc.IsValid());

  // Clear an unset attribute.
  EXPECT_TRUE(pc.SetDomain(std::string()));
  EXPECT_FALSE(pc.HasDomain());
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  // Set a string containing an invalid character
  EXPECT_FALSE(pc.SetDomain("foo;bar"));
  EXPECT_FALSE(pc.HasDomain());
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_TRUE(pc.IsValid());

  // Set all other attributes and check that they are appended in order.
  EXPECT_TRUE(pc.SetDomain("domain.com"));
  EXPECT_TRUE(pc.SetPath("/"));
  EXPECT_TRUE(pc.SetExpires("Sun, 18-Apr-2027 21:06:29 GMT"));
  EXPECT_TRUE(pc.SetMaxAge("12345"));
  EXPECT_TRUE(pc.SetIsSecure(true));
  EXPECT_TRUE(pc.SetIsHttpOnly(true));
  EXPECT_TRUE(pc.SetIsHttpOnly(true));
  EXPECT_TRUE(pc.SetPriority("HIGH"));
  EXPECT_EQ("name=value; domain=domain.com; path=/; "
            "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; "
            "httponly; priority=HIGH",
            pc.ToCookieLine());
  EXPECT_TRUE(pc.HasDomain());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_TRUE(pc.HasExpires());
  EXPECT_TRUE(pc.HasMaxAge());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.IsHttpOnly());
  EXPECT_EQ(COOKIE_PRIORITY_HIGH, pc.Priority());

  // Clear one attribute from the middle.
  EXPECT_TRUE(pc.SetPath("/foo"));
  EXPECT_TRUE(pc.HasDomain());
  EXPECT_TRUE(pc.HasPath());
  EXPECT_TRUE(pc.HasExpires());
  EXPECT_TRUE(pc.IsSecure());
  EXPECT_TRUE(pc.IsHttpOnly());
  EXPECT_EQ("name=value; domain=domain.com; path=/foo; "
            "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; "
            "httponly; priority=HIGH",
            pc.ToCookieLine());

  // Set priority to medium.
  EXPECT_TRUE(pc.SetPriority("medium"));
  EXPECT_EQ("name=value; domain=domain.com; path=/foo; "
            "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; "
            "httponly; priority=medium",
            pc.ToCookieLine());

  // Clear the rest and change the name and value.
  EXPECT_TRUE(pc.SetDomain(std::string()));
  EXPECT_TRUE(pc.SetPath(std::string()));
  EXPECT_TRUE(pc.SetExpires(std::string()));
  EXPECT_TRUE(pc.SetMaxAge(std::string()));
  EXPECT_TRUE(pc.SetIsSecure(false));
  EXPECT_TRUE(pc.SetIsHttpOnly(false));
  EXPECT_TRUE(pc.SetName("name2"));
  EXPECT_TRUE(pc.SetValue("value2"));
  EXPECT_TRUE(pc.SetPriority(std::string()));
  EXPECT_FALSE(pc.HasDomain());
  EXPECT_FALSE(pc.HasPath());
  EXPECT_FALSE(pc.HasExpires());
  EXPECT_FALSE(pc.HasMaxAge());
  EXPECT_FALSE(pc.IsSecure());
  EXPECT_FALSE(pc.IsHttpOnly());
  EXPECT_EQ("name2=value2", pc.ToCookieLine());
}

TEST(ParsedCookieTest, SetPriority) {
  ParsedCookie pc("name=value");
  EXPECT_TRUE(pc.IsValid());

  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());

  // Test each priority, expect case-insensitive compare.
  EXPECT_TRUE(pc.SetPriority("high"));
  EXPECT_EQ("name=value; priority=high", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_HIGH, pc.Priority());

  EXPECT_TRUE(pc.SetPriority("mEDium"));
  EXPECT_EQ("name=value; priority=mEDium", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, pc.Priority());

  EXPECT_TRUE(pc.SetPriority("LOW"));
  EXPECT_EQ("name=value; priority=LOW", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_LOW, pc.Priority());

  // Interpret invalid priority values as COOKIE_PRIORITY_DEFAULT.
  EXPECT_TRUE(pc.SetPriority("Blah"));
  EXPECT_EQ("name=value; priority=Blah", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());

  EXPECT_TRUE(pc.SetPriority("lowerest"));
  EXPECT_EQ("name=value; priority=lowerest", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());

  EXPECT_TRUE(pc.SetPriority(""));
  EXPECT_EQ("name=value", pc.ToCookieLine());
  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
}

TEST(ParsedCookieTest, InvalidNonAlphanumericChars) {
  ParsedCookie pc1("name=\x05");
  ParsedCookie pc2("name=foo" "\x1c" "bar");
  ParsedCookie pc3("name=foobar" "\x11");
  ParsedCookie pc4("name=\x02" "foobar");

  ParsedCookie pc5("\x05=value");
  ParsedCookie pc6("foo" "\x05" "bar=value");
  ParsedCookie pc7("foobar" "\x05" "=value");
  ParsedCookie pc8("\x05" "foobar" "=value");

  ParsedCookie pc9("foo" "\x05" "bar" "=foo" "\x05" "bar");

  ParsedCookie pc10("foo=bar;ba" "\x05" "z=boo");
  ParsedCookie pc11("foo=bar;baz=bo" "\x05" "o");
  ParsedCookie pc12("foo=bar;ba" "\05" "z=bo" "\x05" "o");

  EXPECT_FALSE(pc1.IsValid());
  EXPECT_FALSE(pc2.IsValid());
  EXPECT_FALSE(pc3.IsValid());
  EXPECT_FALSE(pc4.IsValid());
  EXPECT_FALSE(pc5.IsValid());
  EXPECT_FALSE(pc6.IsValid());
  EXPECT_FALSE(pc7.IsValid());
  EXPECT_FALSE(pc8.IsValid());
  EXPECT_FALSE(pc9.IsValid());
  EXPECT_FALSE(pc10.IsValid());
  EXPECT_FALSE(pc11.IsValid());
  EXPECT_FALSE(pc12.IsValid());
}

TEST(ParsedCookieTest, ValidNonAlphanumericChars) {
  // Note that some of these words are pasted backwords thanks to poor vim bidi
  // support. This should not affect the tests, however.
  const char* pc1_literal = "name=العربية";
  const char* pc2_literal = "name=普通話";
  const char* pc3_literal = "name=ภาษาไทย";
  const char* pc4_literal = "name=עִבְרִית";
  const char* pc5_literal = "العربية=value";
  const char* pc6_literal = "普通話=value";
  const char* pc7_literal = "ภาษาไทย=value";
  const char* pc8_literal = "עִבְרִית=value";
  ParsedCookie pc1(pc1_literal);
  ParsedCookie pc2(pc2_literal);
  ParsedCookie pc3(pc3_literal);
  ParsedCookie pc4(pc4_literal);
  ParsedCookie pc5(pc5_literal);
  ParsedCookie pc6(pc6_literal);
  ParsedCookie pc7(pc7_literal);
  ParsedCookie pc8(pc8_literal);

  EXPECT_TRUE(pc1.IsValid());
  EXPECT_EQ(pc1_literal, pc1.ToCookieLine());
  EXPECT_TRUE(pc2.IsValid());
  EXPECT_EQ(pc2_literal, pc2.ToCookieLine());
  EXPECT_TRUE(pc3.IsValid());
  EXPECT_EQ(pc3_literal, pc3.ToCookieLine());
  EXPECT_TRUE(pc4.IsValid());
  EXPECT_EQ(pc4_literal, pc4.ToCookieLine());
  EXPECT_TRUE(pc5.IsValid());
  EXPECT_EQ(pc5_literal, pc5.ToCookieLine());
  EXPECT_TRUE(pc6.IsValid());
  EXPECT_EQ(pc6_literal, pc6.ToCookieLine());
  EXPECT_TRUE(pc7.IsValid());
  EXPECT_EQ(pc7_literal, pc7.ToCookieLine());
  EXPECT_TRUE(pc8.IsValid());
  EXPECT_EQ(pc8_literal, pc8.ToCookieLine());
}

}

/* [<][>][^][v][top][bottom][index][help] */