summaryrefslogtreecommitdiff
path: root/chromium/net/cookies
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2013-12-11 21:33:03 +0100
committerAndras Becsi <andras.becsi@digia.com>2013-12-13 12:34:07 +0100
commitf2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch)
tree0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/net/cookies
parent5362912cdb5eea702b68ebe23702468d17c3017a (diff)
downloadqtwebengine-chromium-f2a33ff9cbc6d19943f1c7fbddd1f23d23975577.tar.gz
Update Chromium to branch 1650 (31.0.1650.63)
Change-Id: I57d8c832eaec1eb2364e0a8e7352a6dd354db99f Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'chromium/net/cookies')
-rw-r--r--chromium/net/cookies/cookie_monster.cc45
-rw-r--r--chromium/net/cookies/cookie_monster.h16
-rw-r--r--chromium/net/cookies/cookie_monster_perftest.cc28
-rw-r--r--chromium/net/cookies/cookie_monster_unittest.cc41
-rw-r--r--chromium/net/cookies/parsed_cookie.cc59
-rw-r--r--chromium/net/cookies/parsed_cookie_unittest.cc71
6 files changed, 194 insertions, 66 deletions
diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc
index f24637735fd..65723ff20a6 100644
--- a/chromium/net/cookies/cookie_monster.cc
+++ b/chromium/net/cookies/cookie_monster.cc
@@ -112,6 +112,15 @@ const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
namespace {
+bool ContainsControlCharacter(const std::string& s) {
+ for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
+ if ((*i >= 0) && (*i <= 31))
+ return true;
+ }
+
+ return false;
+}
+
typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
// Default minimum delay after updating a cookie's LastAccessDate before we
@@ -286,6 +295,8 @@ ChangeCausePair ChangeCauseMapping[] = {
{ CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
// DELETE_COOKIE_EXPIRED_OVERWRITE
{ CookieMonster::Delegate::CHANGE_COOKIE_EXPIRED_OVERWRITE, true },
+ // DELETE_COOKIE_CONTROL_CHAR
+ { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true},
// DELETE_COOKIE_LAST_ENTRY
{ CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false }
};
@@ -1477,16 +1488,24 @@ void CookieMonster::StoreLoadedCookies(
// and sync'd.
base::AutoLock autolock(lock_);
+ CookieItVector cookies_with_control_chars;
+
for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue();
if (creation_times_.insert(cookie_creation_time).second) {
- InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
+ CookieMap::iterator inserted =
+ InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
const Time cookie_access_time((*it)->LastAccessDate());
if (earliest_access_time_.is_null() ||
cookie_access_time < earliest_access_time_)
earliest_access_time_ = cookie_access_time;
+
+ if (ContainsControlCharacter((*it)->Name()) ||
+ ContainsControlCharacter((*it)->Value())) {
+ cookies_with_control_chars.push_back(inserted);
+ }
} else {
LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation "
"times in backing store: "
@@ -1500,6 +1519,16 @@ void CookieMonster::StoreLoadedCookies(
}
}
+ // Any cookies that contain control characters that we have loaded from the
+ // persistent store should be deleted. See http://crbug.com/238041.
+ for (CookieItVector::iterator it = cookies_with_control_chars.begin();
+ it != cookies_with_control_chars.end();) {
+ CookieItVector::iterator curit = it;
+ ++it;
+
+ InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
+ }
+
// After importing cookies from the PersistentCookieStore, verify that
// none of our other constraints are violated.
// In particular, the backing store might have given us duplicate cookies.
@@ -1733,19 +1762,23 @@ bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
return skipped_httponly;
}
-void CookieMonster::InternalInsertCookie(const std::string& key,
- CanonicalCookie* cc,
- bool sync_to_store) {
+CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
+ const std::string& key,
+ CanonicalCookie* cc,
+ bool sync_to_store) {
lock_.AssertAcquired();
if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
sync_to_store)
store_->AddCookie(*cc);
- cookies_.insert(CookieMap::value_type(key, cc));
+ CookieMap::iterator inserted =
+ cookies_.insert(CookieMap::value_type(key, cc));
if (delegate_.get()) {
delegate_->OnCookieChanged(
*cc, false, CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT);
}
+
+ return inserted;
}
bool CookieMonster::SetCookieWithCreationTimeAndOptions(
@@ -1831,6 +1864,8 @@ void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
store_->UpdateCookieAccessTime(*cc);
}
+// InternalDeleteCookies must not invalidate iterators other than the one being
+// deleted.
void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
bool sync_to_store,
DeletionCause deletion_cause) {
diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h
index eaf89d33810..1df616cd6d9 100644
--- a/chromium/net/cookies/cookie_monster.h
+++ b/chromium/net/cookies/cookie_monster.h
@@ -379,6 +379,11 @@ class NET_EXPORT CookieMonster : public CookieStore {
// already-expired expiration date. This captures that case.
DELETE_COOKIE_EXPIRED_OVERWRITE,
+ // Cookies are not allowed to contain control characters in the name or
+ // value. However, we used to allow them, so we are now evicting any such
+ // cookies as we load them. See http://crbug.com/238041.
+ DELETE_COOKIE_CONTROL_CHAR,
+
DELETE_COOKIE_LAST_ENTRY
};
@@ -517,10 +522,11 @@ class NET_EXPORT CookieMonster : public CookieStore {
bool skip_httponly,
bool already_expired);
- // Takes ownership of *cc.
- void InternalInsertCookie(const std::string& key,
- CanonicalCookie* cc,
- bool sync_to_store);
+ // Takes ownership of *cc. Returns an iterator that points to the inserted
+ // cookie in cookies_. Guarantee: all iterators to cookies_ remain valid.
+ CookieMap::iterator InternalInsertCookie(const std::string& key,
+ CanonicalCookie* cc,
+ bool sync_to_store);
// Helper function that sets cookies with more control.
// Not exposed as we don't want callers to have the ability
@@ -541,6 +547,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
// |deletion_cause| argument is used for collecting statistics and choosing
// the correct Delegate::ChangeCause for OnCookieChanged notifications.
+ // Guarantee: All iterators to cookies_ except to the deleted entry remain
+ // vaild.
void InternalDeleteCookie(CookieMap::iterator it, bool sync_to_store,
DeletionCause deletion_cause);
diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc
index c70516f70eb..2bc0be8480c 100644
--- a/chromium/net/cookies/cookie_monster_perftest.cc
+++ b/chromium/net/cookies/cookie_monster_perftest.cc
@@ -6,9 +6,9 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
-#include "base/perftimer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/test/perf_time_logger.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_monster_store_test.h"
@@ -97,7 +97,7 @@ class GetCookiesCallback : public BaseCallback {
TEST(ParsedCookieTest, TestParseCookies) {
std::string cookie(kCookieLine);
- PerfTimeLogger timer("Parsed_cookie_parse_cookies");
+ base::PerfTimeLogger timer("Parsed_cookie_parse_cookies");
for (int i = 0; i < kNumCookies; ++i) {
ParsedCookie pc(cookie);
EXPECT_TRUE(pc.IsValid());
@@ -108,7 +108,7 @@ TEST(ParsedCookieTest, TestParseCookies) {
TEST(ParsedCookieTest, TestParseBigCookies) {
std::string cookie(3800, 'z');
cookie += kCookieLine;
- PerfTimeLogger timer("Parsed_cookie_parse_big_cookies");
+ base::PerfTimeLogger timer("Parsed_cookie_parse_big_cookies");
for (int i = 0; i < kNumCookies; ++i) {
ParsedCookie pc(cookie);
EXPECT_TRUE(pc.IsValid());
@@ -126,7 +126,7 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) {
SetCookieCallback setCookieCallback;
// Add a bunch of cookies on a single host
- PerfTimeLogger timer("Cookie_monster_add_single_host");
+ base::PerfTimeLogger timer("Cookie_monster_add_single_host");
for (std::vector<std::string>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
@@ -136,14 +136,14 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) {
GetCookiesCallback getCookiesCallback;
- PerfTimeLogger timer2("Cookie_monster_query_single_host");
+ base::PerfTimeLogger timer2("Cookie_monster_query_single_host");
for (std::vector<std::string>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
getCookiesCallback.GetCookies(cm.get(), GURL(kGoogleURL));
}
timer2.Done();
- PerfTimeLogger timer3("Cookie_monster_deleteall_single_host");
+ base::PerfTimeLogger timer3("Cookie_monster_deleteall_single_host");
cm->DeleteAllAsync(CookieMonster::DeleteCallback());
base::MessageLoop::current()->RunUntilIdle();
timer3.Done();
@@ -160,7 +160,7 @@ TEST_F(CookieMonsterTest, TestAddCookieOnManyHosts) {
SetCookieCallback setCookieCallback;
// Add a cookie on a bunch of host
- PerfTimeLogger timer("Cookie_monster_add_many_hosts");
+ base::PerfTimeLogger timer("Cookie_monster_add_many_hosts");
for (std::vector<GURL>::const_iterator it = gurls.begin();
it != gurls.end(); ++it) {
setCookieCallback.SetCookie(cm.get(), *it, cookie);
@@ -169,14 +169,14 @@ TEST_F(CookieMonsterTest, TestAddCookieOnManyHosts) {
GetCookiesCallback getCookiesCallback;
- PerfTimeLogger timer2("Cookie_monster_query_many_hosts");
+ base::PerfTimeLogger timer2("Cookie_monster_query_many_hosts");
for (std::vector<GURL>::const_iterator it = gurls.begin();
it != gurls.end(); ++it) {
getCookiesCallback.GetCookies(cm.get(), *it);
}
timer2.Done();
- PerfTimeLogger timer3("Cookie_monster_deleteall_many_hosts");
+ base::PerfTimeLogger timer3("Cookie_monster_deleteall_many_hosts");
cm->DeleteAllAsync(CookieMonster::DeleteCallback());
base::MessageLoop::current()->RunUntilIdle();
timer3.Done();
@@ -229,7 +229,7 @@ TEST_F(CookieMonsterTest, TestDomainTree) {
std::string cookie_line = getCookiesCallback.GetCookies(cm.get(), probe_gurl);
EXPECT_EQ(5, CountInString(cookie_line, '='))
<< "Cookie line: " << cookie_line;
- PerfTimeLogger timer("Cookie_monster_query_domain_tree");
+ base::PerfTimeLogger timer("Cookie_monster_query_domain_tree");
for (int i = 0; i < kNumCookies; i++) {
getCookiesCallback.GetCookies(cm.get(), probe_gurl);
}
@@ -269,7 +269,7 @@ TEST_F(CookieMonsterTest, TestDomainLine) {
cookie_line = getCookiesCallback.GetCookies(cm.get(), probe_gurl);
EXPECT_EQ(32, CountInString(cookie_line, '='));
- PerfTimeLogger timer2("Cookie_monster_query_domain_line");
+ base::PerfTimeLogger timer2("Cookie_monster_query_domain_line");
for (int i = 0; i < kNumCookies; i++) {
getCookiesCallback.GetCookies(cm.get(), probe_gurl);
}
@@ -304,7 +304,7 @@ TEST_F(CookieMonsterTest, TestImport) {
// Import will happen on first access.
GURL gurl("www.google.com");
CookieOptions options;
- PerfTimeLogger timer("Cookie_monster_import_from_store");
+ base::PerfTimeLogger timer("Cookie_monster_import_from_store");
getCookiesCallback.GetCookies(cm.get(), gurl);
timer.Done();
@@ -314,7 +314,7 @@ TEST_F(CookieMonsterTest, TestImport) {
TEST_F(CookieMonsterTest, TestGetKey) {
scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
- PerfTimeLogger timer("Cookie_monster_get_key");
+ base::PerfTimeLogger timer("Cookie_monster_get_key");
for (int i = 0; i < kNumCookies; i++)
cm->GetKey("www.google.com");
timer.Done();
@@ -375,7 +375,7 @@ TEST_F(CookieMonsterTest, TestGCTimes) {
// Trigger the Garbage collection we're allowed.
setCookieCallback.SetCookie(cm.get(), gurl, cookie_line);
- PerfTimeLogger timer((std::string("GC_") + test_case.name).c_str());
+ base::PerfTimeLogger timer((std::string("GC_") + test_case.name).c_str());
for (int i = 0; i < kNumCookies; i++)
setCookieCallback.SetCookie(cm.get(), gurl, cookie_line);
timer.Done();
diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc
index d1ce04f3885..2bfe9ee9978 100644
--- a/chromium/net/cookies/cookie_monster_unittest.cc
+++ b/chromium/net/cookies/cookie_monster_unittest.cc
@@ -2685,4 +2685,45 @@ TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
EXPECT_EQ(5u, store->commands().size());
}
+// Test to assure that cookies with control characters are purged appropriately.
+// See http://crbug.com/238041 for background.
+TEST_F(CookieMonsterTest, ControlCharacterPurge) {
+ const Time now1(Time::Now());
+ const Time now2(Time::Now() + TimeDelta::FromSeconds(1));
+ const Time now3(Time::Now() + TimeDelta::FromSeconds(2));
+ const Time later(now1 + TimeDelta::FromDays(1));
+ const GURL url("http://host/path");
+ const std::string domain("host");
+ const std::string path("/path");
+
+ scoped_refptr<MockPersistentCookieStore> store(
+ new MockPersistentCookieStore);
+
+ std::vector<CanonicalCookie*> initial_cookies;
+
+ AddCookieToList(domain,
+ "foo=bar; path=" + path,
+ now1,
+ &initial_cookies);
+
+ // We have to manually build this cookie because it contains a control
+ // character, and our cookie line parser rejects control characters.
+ CanonicalCookie *cc = new CanonicalCookie(url, "baz", "\x05" "boo", domain,
+ path, now2, later, now2, false,
+ false, COOKIE_PRIORITY_DEFAULT);
+ initial_cookies.push_back(cc);
+
+ AddCookieToList(domain,
+ "hello=world; path=" + path,
+ now3,
+ &initial_cookies);
+
+ // Inject our initial cookies into the mock PersistentCookieStore.
+ store->SetLoadExpectation(true, initial_cookies);
+
+ scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
+
+ EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url));
+}
+
} // namespace net
diff --git a/chromium/net/cookies/parsed_cookie.cc b/chromium/net/cookies/parsed_cookie.cc
index 125d3d998b9..60e0bbb6618 100644
--- a/chromium/net/cookies/parsed_cookie.cc
+++ b/chromium/net/cookies/parsed_cookie.cc
@@ -45,20 +45,8 @@
#include "net/cookies/parsed_cookie.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
-// TODO(jww): We are collecting several UMA statistics in this file, and they
-// relate to http://crbug.com/238041. We are measuring stats related to control
-// characters in cookies because, currently, we allow control characters in a
-// variety of scenarios where various RFCs theoretically disallow them. These
-// control characters have the potential to cause problems with certain web
-// servers that reject HTTP requests that contain cookies with control
-// characters. We are measuring whether disallowing such cookies would have a
-// notable impact on our users. We want to collect these stats through 1 stable
-// release, so these UMA stats should remain at least through the M29
-// branch-point.
-
namespace {
const char kPathTokenName[] = "path";
@@ -148,11 +136,15 @@ bool IsValidCookieValue(const std::string& value) {
return true;
}
+bool IsControlCharacter(unsigned char c) {
+ return (c >= 0) && (c <= 31);
+}
+
bool IsValidCookieAttributeValue(const std::string& value) {
// The greatest common denominator of cookie attribute values is
// <any CHAR except CTLs or ";"> according to RFC 6265.
for (std::string::const_iterator i = value.begin(); i != value.end(); ++i) {
- if ((*i >= 0 && *i <= 31) || *i == ';')
+ if (IsControlCharacter(*i) || *i == ';')
return false;
}
return true;
@@ -194,9 +186,7 @@ CookiePriority ParsedCookie::Priority() const {
}
bool ParsedCookie::SetName(const std::string& name) {
- bool valid_token = IsValidToken(name);
- UMA_HISTOGRAM_BOOLEAN("Cookie.SetNameVaildity", valid_token);
- if (!valid_token)
+ if (!IsValidToken(name))
return false;
if (pairs_.empty())
pairs_.push_back(std::make_pair("", ""));
@@ -205,10 +195,7 @@ bool ParsedCookie::SetName(const std::string& name) {
}
bool ParsedCookie::SetValue(const std::string& value) {
- bool valid_cookie_value = IsValidCookieValue(value);
- UMA_HISTOGRAM_BOOLEAN("Cookie.SetValueCookieValueValidity",
- valid_cookie_value);
- if (!valid_cookie_value)
+ if (!IsValidCookieValue(value))
return false;
if (pairs_.empty())
pairs_.push_back(std::make_pair("", ""));
@@ -354,15 +341,6 @@ std::string ParsedCookie::ParseValueString(const std::string& value) {
// Parse all token/value pairs and populate pairs_.
void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
- enum ParsedCookieStatus {
- PARSED_COOKIE_STATUS_NOTHING = 0x0,
- PARSED_COOKIE_STATUS_CONTROL_CHAR = 0x1,
- PARSED_COOKIE_STATUS_INVALID = 0x2,
- PARSED_COOKIE_STATUS_BOTH =
- PARSED_COOKIE_STATUS_CONTROL_CHAR | PARSED_COOKIE_STATUS_INVALID
- };
- int parsed_cookie_status = PARSED_COOKIE_STATUS_NOTHING;
-
pairs_.clear();
// Ok, here we go. We should be expecting to be starting somewhere
@@ -407,17 +385,21 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
// OK, now try to parse a value.
std::string::const_iterator value_start, value_end;
ParseValue(&it, end, &value_start, &value_end);
+
// OK, we're finished with a Token/Value.
pair.second = std::string(value_start, value_end);
- if (!IsValidCookieAttributeValue(pair.second))
- parsed_cookie_status |= PARSED_COOKIE_STATUS_CONTROL_CHAR;
- if (!IsValidToken(pair.second))
- parsed_cookie_status |= PARSED_COOKIE_STATUS_INVALID;
-
// From RFC2109: "Attributes (names) (attr) are case-insensitive."
if (pair_num != 0)
StringToLowerASCII(&pair.first);
+ // Ignore Set-Cookie directives contaning control characters. See
+ // http://crbug.com/238041.
+ if (!IsValidCookieAttributeValue(pair.first) ||
+ !IsValidCookieAttributeValue(pair.second)) {
+ pairs_.clear();
+ break;
+ }
+
pairs_.push_back(pair);
// We've processed a token/value pair, we're either at the end of
@@ -425,9 +407,6 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
if (it != end)
++it;
}
-
- UMA_HISTOGRAM_ENUMERATION("Cookie.ParsedCookieStatus", parsed_cookie_status,
- PARSED_COOKIE_STATUS_BOTH + 1);
}
void ParsedCookie::SetupAttributes() {
@@ -478,11 +457,7 @@ bool ParsedCookie::SetBool(size_t* index,
bool ParsedCookie::SetAttributePair(size_t* index,
const std::string& key,
const std::string& value) {
- bool valid_attribute_pair = IsValidToken(key) &&
- IsValidCookieAttributeValue(value);
- UMA_HISTOGRAM_BOOLEAN("Cookie.SetAttributePairCharsValidity",
- valid_attribute_pair);
- if (!valid_attribute_pair)
+ if (!(IsValidToken(key) && IsValidCookieAttributeValue(value)))
return false;
if (!IsValid())
return false;
diff --git a/chromium/net/cookies/parsed_cookie_unittest.cc b/chromium/net/cookies/parsed_cookie_unittest.cc
index ad4aba65d79..23e3768afe6 100644
--- a/chromium/net/cookies/parsed_cookie_unittest.cc
+++ b/chromium/net/cookies/parsed_cookie_unittest.cc
@@ -422,4 +422,73 @@ TEST(ParsedCookieTest, SetPriority) {
EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
}
-} // namespace net
+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());
+}
+
+}