Adding Priority field to cookies.

This CL focuses on cookie parser, CanonicalCookie, and making callers pass PRIORITY_DEFAULT where applicable.

What's NOT included in this CL:
- TODO(rogerm): Persistence in SQL database.
- TODO(huangs): Using cookie priority to affect cookie eviction.
- TODO(huangs): Make priorities available for extension API (right now default value is used to set).
- TODO(lower priority): Cookie viewer update.
- TODO(lower priority): WebCookie update in webkit/glue.

BUG=232693

Review URL: https://codereview.chromium.org/14113014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195245 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 228e3f3..4b05be4 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -113,7 +113,8 @@
     const GURL& url, const std::string& name, const std::string& value,
     const std::string& domain, const std::string& path,
     const base::Time& creation, const base::Time& expiration,
-    const base::Time& last_access, bool secure, bool httponly)
+    const base::Time& last_access, bool secure, bool httponly,
+    CookiePriority priority)
     : source_(GetCookieSourceFromURL(url)),
       name_(name),
       value_(value),
@@ -123,7 +124,8 @@
       expiry_date_(expiration),
       last_access_date_(last_access),
       secure_(secure),
-      httponly_(httponly) {
+      httponly_(httponly),
+      priority_(priority) {
 }
 
 CanonicalCookie::CanonicalCookie(const GURL& url, const ParsedCookie& pc)
@@ -134,7 +136,8 @@
       creation_date_(Time::Now()),
       last_access_date_(Time()),
       secure_(pc.IsSecure()),
-      httponly_(pc.IsHttpOnly()) {
+      httponly_(pc.IsHttpOnly()),
+      priority_(pc.Priority()) {
   if (pc.HasExpires())
     expiry_date_ = CanonExpiration(pc, creation_date_, creation_date_);
 
@@ -239,7 +242,8 @@
                              cookie_domain, cookie_path, creation_time,
                              cookie_expires, creation_time,
                              parsed_cookie.IsSecure(),
-                             parsed_cookie.IsHttpOnly());
+                             parsed_cookie.IsHttpOnly(),
+                             parsed_cookie.Priority());
 }
 
 CanonicalCookie* CanonicalCookie::Create(const GURL& url,
@@ -250,7 +254,8 @@
                                          const base::Time& creation,
                                          const base::Time& expiration,
                                          bool secure,
-                                         bool http_only) {
+                                         bool http_only,
+                                         CookiePriority priority) {
   // Expect valid attribute tokens and values, as defined by the ParsedCookie
   // logic, otherwise don't create the cookie.
   std::string parsed_name = ParsedCookie::ParseTokenString(name);
@@ -288,7 +293,7 @@
 
   return new CanonicalCookie(url, parsed_name, parsed_value, cookie_domain,
                              cookie_path, creation, expiration, creation,
-                             secure, http_only);
+                             secure, http_only, priority);
 }
 
 bool CanonicalCookie::IsOnPath(const std::string& url_path) const {
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 6c9a2228..341f58b1 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -11,6 +11,7 @@
 #include "base/basictypes.h"
 #include "base/time.h"
 #include "net/base/net_export.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_options.h"
 
 class GURL;
@@ -35,7 +36,8 @@
                   const base::Time& expiration,
                   const base::Time& last_access,
                   bool secure,
-                  bool httponly);
+                  bool httponly,
+                  CookiePriority priority);
 
   // This constructor does canonicalization but not validation.
   // The result of this constructor should not be relied on in contexts
@@ -65,7 +67,8 @@
                                  const base::Time& creation,
                                  const base::Time& expiration,
                                  bool secure,
-                                 bool http_only);
+                                 bool http_only,
+                                 CookiePriority priority);
 
   const std::string& Source() const { return source_; }
   const std::string& Name() const { return name_; }
@@ -78,6 +81,7 @@
   const base::Time& ExpiryDate() const { return expiry_date_; }
   bool IsSecure() const { return secure_; }
   bool IsHttpOnly() const { return httponly_; }
+  CookiePriority Priority() const { return priority_; }
   bool IsDomainCookie() const {
     return !domain_.empty() && domain_[0] == '.'; }
   bool IsHostCookie() const { return !IsDomainCookie(); }
@@ -148,6 +152,7 @@
   base::Time last_access_date_;
   bool secure_;
   bool httponly_;
+  CookiePriority priority_;
 };
 
 typedef std::vector<CanonicalCookie> CookieList;
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index 161b27f..a9eda310 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "googleurl/src/gurl.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_options.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,8 +47,8 @@
   base::Time current_time = base::Time::Now();
 
   CanonicalCookie cookie(url, "A", "2", "www.example.com", "/test",
-                         current_time, base::Time(), current_time, false,
-                         false);
+                         current_time, base::Time(), current_time, false, false,
+                         COOKIE_PRIORITY_DEFAULT);
   EXPECT_EQ(url.GetOrigin().spec(), cookie.Source());
   EXPECT_EQ("A", cookie.Name());
   EXPECT_EQ("2", cookie.Value());
@@ -64,7 +65,8 @@
                           base::Time(),
                           current_time,
                           false,
-                          false);
+                          false,
+                          COOKIE_PRIORITY_DEFAULT);
   EXPECT_EQ(url.GetOrigin().spec(), cookie.Source());
   EXPECT_EQ("A", cookie2.Name());
   EXPECT_EQ("2", cookie2.Value());
@@ -120,7 +122,7 @@
   // string.
   cookie.reset(CanonicalCookie::Create(
       url, "A", "2", "www.example.com", "/test", creation_time, base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_EQ(url.GetOrigin().spec(), cookie->Source());
   EXPECT_EQ("A", cookie->Name());
   EXPECT_EQ("2", cookie->Value());
@@ -130,7 +132,7 @@
 
   cookie.reset(CanonicalCookie::Create(
       url, "A", "2", ".www.example.com", "/test", creation_time, base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_EQ(url.GetOrigin().spec(), cookie->Source());
   EXPECT_EQ("A", cookie->Name());
   EXPECT_EQ("2", cookie->Value());
@@ -188,14 +190,16 @@
   scoped_ptr<CanonicalCookie> cookie(
       new CanonicalCookie(url, cookie_name, cookie_value, cookie_domain,
                           cookie_path, creation_time, expiration_time,
-                          last_access_time, secure, httponly));
+                          last_access_time, secure, httponly,
+                          COOKIE_PRIORITY_MEDIUM));
   EXPECT_TRUE(cookie->IsEquivalent(*cookie));
 
   // Test that two identical cookies are equivalent.
   scoped_ptr<CanonicalCookie> other_cookie(
       new CanonicalCookie(url, cookie_name, cookie_value, cookie_domain,
                           cookie_path, creation_time, expiration_time,
-                          last_access_time, secure, httponly));
+                          last_access_time, secure, httponly,
+                          COOKIE_PRIORITY_MEDIUM));
   EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
 
   // Tests that use different variations of attribute values that
@@ -203,7 +207,8 @@
   other_cookie.reset(new CanonicalCookie(url, cookie_name, "2", cookie_domain,
                                          cookie_path, creation_time,
                                          expiration_time, last_access_time,
-                                         secure, httponly));
+                                         secure, httponly,
+                                         COOKIE_PRIORITY_HIGH));
   EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
 
   base::Time other_creation_time =
@@ -211,13 +216,15 @@
   other_cookie.reset(new CanonicalCookie(url, cookie_name, "2", cookie_domain,
                                          cookie_path, other_creation_time,
                                          expiration_time, last_access_time,
-                                         secure, httponly));
+                                         secure, httponly,
+                                         COOKIE_PRIORITY_MEDIUM));
   EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
 
   other_cookie.reset(new CanonicalCookie(url, cookie_name, cookie_name,
                                          cookie_domain, cookie_path,
                                          creation_time, expiration_time,
-                                         last_access_time, true, httponly));
+                                         last_access_time, true, httponly,
+                                         COOKIE_PRIORITY_LOW));
   EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
 
   // Tests that use different variations of attribute values that
@@ -225,13 +232,15 @@
   other_cookie.reset(new CanonicalCookie(url, "B", cookie_value, cookie_domain,
                                          cookie_path, creation_time,
                                          expiration_time, last_access_time,
-                                         secure, httponly));
+                                         secure, httponly,
+                                         COOKIE_PRIORITY_MEDIUM));
   EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
 
   other_cookie.reset(new CanonicalCookie(url, cookie_name, cookie_value,
                                          "www.example.com", cookie_path,
                                          creation_time, expiration_time,
-                                         last_access_time, secure, httponly));
+                                         last_access_time, secure, httponly,
+                                         COOKIE_PRIORITY_MEDIUM));
   EXPECT_TRUE(cookie->IsDomainCookie());
   EXPECT_FALSE(other_cookie->IsDomainCookie());
   EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
@@ -239,13 +248,15 @@
   other_cookie.reset(new CanonicalCookie(url, cookie_name, cookie_value,
                                          ".example.com", cookie_path,
                                          creation_time, expiration_time,
-                                         last_access_time, secure, httponly));
+                                         last_access_time, secure, httponly,
+                                         COOKIE_PRIORITY_MEDIUM));
   EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
 
   other_cookie.reset(new CanonicalCookie(url, cookie_name, cookie_value,
                                          cookie_domain, "/test/0",
                                          creation_time, expiration_time,
-                                         last_access_time, secure, httponly));
+                                         last_access_time, secure, httponly,
+                                         COOKIE_PRIORITY_MEDIUM));
   EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
 }
 
diff --git a/net/cookies/cookie_constants.cc b/net/cookies/cookie_constants.cc
new file mode 100644
index 0000000..ba76f2c
--- /dev/null
+++ b/net/cookies/cookie_constants.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 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 "net/cookies/cookie_constants.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace net {
+
+namespace {
+const char kPriorityLow[] = "low";
+const char kPriorityMedium[] = "medium";
+const char kPriorityHigh[] = "high";
+}  // namespace
+
+NET_EXPORT const std::string CookiePriorityToString(CookiePriority priority) {
+  switch(priority) {
+    case COOKIE_PRIORITY_HIGH:
+      return kPriorityHigh;
+    case COOKIE_PRIORITY_MEDIUM:
+      return kPriorityMedium;
+    case COOKIE_PRIORITY_LOW:
+      return kPriorityLow;
+    default:
+      NOTREACHED();
+  }
+  return std::string();
+}
+
+NET_EXPORT CookiePriority StringToCookiePriority(const std::string& priority) {
+  std::string priority_comp(priority);
+  StringToLowerASCII(&priority_comp);
+
+  if (priority_comp == kPriorityHigh)
+    return COOKIE_PRIORITY_HIGH;
+  if (priority_comp == kPriorityMedium)
+    return COOKIE_PRIORITY_MEDIUM;
+  if (priority_comp == kPriorityLow)
+    return COOKIE_PRIORITY_LOW;
+
+  return COOKIE_PRIORITY_DEFAULT;
+}
+
+}  // namespace net
diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
new file mode 100644
index 0000000..7e27e146
--- /dev/null
+++ b/net/cookies/cookie_constants.h
@@ -0,0 +1,30 @@
+// Copyright 2013 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.
+
+#ifndef NET_COOKIES_COOKIE_CONSTANTS_H_
+#define NET_COOKIES_COOKIE_CONSTANTS_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+enum CookiePriority {
+  COOKIE_PRIORITY_LOW     = 0,
+  COOKIE_PRIORITY_MEDIUM  = 1,
+  COOKIE_PRIORITY_HIGH    = 2,
+  COOKIE_PRIORITY_DEFAULT = COOKIE_PRIORITY_MEDIUM
+};
+
+// Returns the Set-Cookie header priority token corresponding to |priority|.
+NET_EXPORT const std::string CookiePriorityToString(CookiePriority priority);
+
+// Converts the Set-Cookie header priority token |priority| to a CookiePriority.
+// Defaults to COOKIE_PRIORITY_DEFAULT for empty or unrecognized strings.
+NET_EXPORT CookiePriority StringToCookiePriority(const std::string& priority);
+
+}  // namespace net
+
+#endif  // NET_COOKIES_COOKIE_CONSTANTS_H_
diff --git a/net/cookies/cookie_constants_unittest.cc b/net/cookies/cookie_constants_unittest.cc
new file mode 100644
index 0000000..f14f11e1
--- /dev/null
+++ b/net/cookies/cookie_constants_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 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 "base/basictypes.h"
+#include "net/cookies/cookie_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(CookieConstantsTest, TestCookiePriority) {
+  // Basic cases.
+  EXPECT_EQ("low", CookiePriorityToString(COOKIE_PRIORITY_LOW));
+  EXPECT_EQ("medium", CookiePriorityToString(COOKIE_PRIORITY_MEDIUM));
+  EXPECT_EQ("high", CookiePriorityToString(COOKIE_PRIORITY_HIGH));
+
+  EXPECT_EQ(COOKIE_PRIORITY_LOW, StringToCookiePriority("low"));
+  EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, StringToCookiePriority("medium"));
+  EXPECT_EQ(COOKIE_PRIORITY_HIGH, StringToCookiePriority("high"));
+
+  // Case Insensitivity of StringToCookiePriority().
+  EXPECT_EQ(COOKIE_PRIORITY_LOW, StringToCookiePriority("LOW"));
+  EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, StringToCookiePriority("Medium"));
+  EXPECT_EQ(COOKIE_PRIORITY_HIGH, StringToCookiePriority("hiGH"));
+
+  // Value of default priority.
+  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, COOKIE_PRIORITY_MEDIUM);
+
+  // Numeric values.
+  EXPECT_LT(COOKIE_PRIORITY_LOW, COOKIE_PRIORITY_MEDIUM);
+  EXPECT_LT(COOKIE_PRIORITY_MEDIUM, COOKIE_PRIORITY_HIGH);
+
+  // Unrecognized tokens are interpreted as COOKIE_PRIORITY_DEFAULT.
+  const char* bad_tokens[] = {"", "lo", "lowerest", "high ", " high", "0"};
+  for (size_t i = 0; i < arraysize(bad_tokens); ++i) {
+    EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, StringToCookiePriority(bad_tokens[i]));
+  }
+}
+
+}  // namespace net
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 61e7f265..29990d8 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -382,6 +382,7 @@
                            const base::Time& expiration_time,
                            bool secure,
                            bool http_only,
+                           CookiePriority priority,
                            const CookieMonster::SetCookiesCallback& callback)
       : CookieMonsterTask(cookie_monster),
         url_(url),
@@ -392,6 +393,7 @@
         expiration_time_(expiration_time),
         secure_(secure),
         http_only_(http_only),
+        priority_(priority),
         callback_(callback) {
   }
 
@@ -410,6 +412,7 @@
   base::Time expiration_time_;
   bool secure_;
   bool http_only_;
+  CookiePriority priority_;
   CookieMonster::SetCookiesCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(SetCookieWithDetailsTask);
@@ -418,7 +421,7 @@
 void CookieMonster::SetCookieWithDetailsTask::Run() {
   bool success = this->cookie_monster()->
       SetCookieWithDetails(url_, name_, value_, domain_, path_,
-                           expiration_time_, secure_, http_only_);
+                           expiration_time_, secure_, http_only_, priority_);
   if (!callback_.is_null()) {
     this->InvokeCallback(base::Bind(&CookieMonster::SetCookiesCallback::Run,
                                     base::Unretained(&callback_), success));
@@ -776,10 +779,11 @@
     const base::Time& expiration_time,
     bool secure,
     bool http_only,
+    CookiePriority priority,
     const SetCookiesCallback& callback) {
   scoped_refptr<SetCookieWithDetailsTask> task =
       new SetCookieWithDetailsTask(this, url, name, value, domain, path,
-                                   expiration_time, secure, http_only,
+                                   expiration_time, secure, http_only, priority,
                                    callback);
 
   DoCookieTaskForURL(task, url);
@@ -935,7 +939,8 @@
                                          const std::string& path,
                                          const base::Time& expiration_time,
                                          bool secure,
-                                         bool http_only) {
+                                         bool http_only,
+                                         CookiePriority priority) {
   base::AutoLock autolock(lock_);
 
   if (!HasCookieableScheme(url))
@@ -945,10 +950,9 @@
   last_time_seen_ = creation_time;
 
   scoped_ptr<CanonicalCookie> cc;
-  cc.reset(CanonicalCookie::Create(
-      url, name, value, domain, path,
-      creation_time, expiration_time,
-      secure, http_only));
+  cc.reset(CanonicalCookie::Create(url, name, value, domain, path,
+                                   creation_time, expiration_time,
+                                   secure, http_only, priority));
 
   if (!cc.get())
     return false;
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 97be706..8395ba9 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -24,6 +24,7 @@
 #include "base/time.h"
 #include "net/base/net_export.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_store.h"
 
 class GURL;
@@ -137,7 +138,9 @@
                                  const std::string& domain,
                                  const std::string& path,
                                  const base::Time& expiration_time,
-                                 bool secure, bool http_only,
+                                 bool secure,
+                                 bool http_only,
+                                 CookiePriority priority,
                                  const SetCookiesCallback& callback);
 
 
@@ -371,7 +374,9 @@
                             const std::string& domain,
                             const std::string& path,
                             const base::Time& expiration_time,
-                            bool secure, bool http_only);
+                            bool secure,
+                            bool http_only,
+                            CookiePriority priority);
 
   CookieList GetAllCookies();
 
diff --git a/net/cookies/cookie_monster_store_test.cc b/net/cookies/cookie_monster_store_test.cc
index 58fb690f..9892fe7 100644
--- a/net/cookies/cookie_monster_store_test.cc
+++ b/net/cookies/cookie_monster_store_test.cc
@@ -9,6 +9,7 @@
 #include "base/stringprintf.h"
 #include "base/time.h"
 #include "googleurl/src/gurl.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -116,7 +117,7 @@
   return CanonicalCookie(
       GURL(), pc.Name(), pc.Value(), key, cookie_path,
       creation_time, cookie_expires, creation_time,
-      pc.IsSecure(), pc.IsHttpOnly());
+      pc.IsSecure(), pc.IsHttpOnly(), pc.Priority());
 }
 
 void AddCookieToList(
@@ -209,7 +210,8 @@
 
     CanonicalCookie cc(
         GURL(), "a", "1", base::StringPrintf("h%05d.izzle", i), "/path",
-        creation_time, expiration_time, last_access_time, false, false);
+        creation_time, expiration_time, last_access_time, false, false,
+        COOKIE_PRIORITY_DEFAULT);
     store->AddCookie(cc);
   }
 
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index b3688c3..90349755 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/time.h"
 #include "googleurl/src/gurl.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_monster_store_test.h"  // For CookieStore mock
 #include "net/cookies/cookie_util.h"
@@ -145,11 +146,14 @@
                             const std::string& domain,
                             const std::string& path,
                             const base::Time& expiration_time,
-                            bool secure, bool http_only) {
+                            bool secure,
+                            bool http_only,
+                            CookiePriority priority) {
     DCHECK(cm);
     SetCookieCallback callback;
     cm->SetCookieWithDetailsAsync(
         url, name, value, domain, path, expiration_time, secure, http_only,
+        priority,
         base::Bind(&SetCookieCallback::Run, base::Unretained(&callback)));
     RunFor(kTimeout);
     EXPECT_TRUE(callback.did_run());
@@ -222,15 +226,18 @@
 
     // Domain cookies
     EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_1,
-                                          "dom_1", "X", ".harvard.edu", "/",
-                                          base::Time(), false, false));
+                                           "dom_1", "X", ".harvard.edu", "/",
+                                           base::Time(), false, false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2,
-                                          "dom_2", "X", ".math.harvard.edu",
-                                           "/", base::Time(), false, false));
+                                           "dom_2", "X", ".math.harvard.edu",
+                                           "/", base::Time(), false, false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_3,
-                                          "dom_3", "X",
-                                          ".bourbaki.math.harvard.edu", "/",
-                                          base::Time(), false, false));
+                                           "dom_3", "X",
+                                           ".bourbaki.math.harvard.edu", "/",
+                                           base::Time(), false, false,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     // Host cookies
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
@@ -241,7 +248,8 @@
                                            "/",
                                            base::Time(),
                                            false,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
                                            url_top_level_domain_plus_2,
                                            "host_2",
@@ -250,7 +258,8 @@
                                            "/",
                                            base::Time(),
                                            false,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
                                            url_top_level_domain_plus_3,
                                            "host_3",
@@ -259,7 +268,8 @@
                                            "/",
                                            base::Time(),
                                            false,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     // Http_only cookie
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
@@ -270,13 +280,15 @@
                                            "/",
                                            base::Time(),
                                            false,
-                                           true));
+                                           true,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     // Secure cookies
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
-                                          url_top_level_domain_plus_2_secure,
-                                         "sec_dom", "X", ".math.harvard.edu",
-                                         "/", base::Time(), true, false));
+                                           url_top_level_domain_plus_2_secure,
+                                           "sec_dom", "X", ".math.harvard.edu",
+                                           "/", base::Time(), true, false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
                                            url_top_level_domain_plus_2_secure,
                                            "sec_host",
@@ -285,17 +297,20 @@
                                            "/",
                                            base::Time(),
                                            true,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     // Domain path cookies
     EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2,
-                                          "dom_path_1", "X",
-                                          ".math.harvard.edu", "/dir1",
-                                          base::Time(), false, false));
+                                           "dom_path_1", "X",
+                                           ".math.harvard.edu", "/dir1",
+                                           base::Time(), false, false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2,
-                                          "dom_path_2", "X",
-                                          ".math.harvard.edu", "/dir1/dir2",
-                                          base::Time(), false, false));
+                                           "dom_path_2", "X",
+                                           ".math.harvard.edu", "/dir1/dir2",
+                                           base::Time(), false, false,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     // Host path cookies
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
@@ -306,7 +321,8 @@
                                            "/dir1",
                                            base::Time(),
                                            false,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
     EXPECT_TRUE(this->SetCookieWithDetails(cm,
                                            url_top_level_domain_plus_2,
                                            "host_path_2",
@@ -315,7 +331,8 @@
                                            "/dir1/dir2",
                                            base::Time(),
                                            false,
-                                           false));
+                                           false,
+                                           COOKIE_PRIORITY_DEFAULT));
 
     EXPECT_EQ(13U, this->GetAllCookies(cm).size());
   }
@@ -452,6 +469,18 @@
   MOCK_METHOD1(Invoke, void(bool success));
 };
 
+struct CookiesInputInfo {
+  const GURL url;
+  const std::string name;
+  const std::string value;
+  const std::string domain;
+  const std::string path;
+  const base::Time expiration_time;
+  bool secure;
+  bool http_only;
+  CookiePriority priority;
+};
+
 ACTION(QuitCurrentMessageLoop) {
   MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
 }
@@ -474,11 +503,10 @@
   cookie_monster->DeleteAllCreatedBetweenAsync(
       delete_begin, delete_end, callback->AsCallback());
 }
-ACTION_P10(SetCookieWithDetailsAction,
-           cookie_monster, url, name, value, domain, path, expiration_time,
-           secure, http_only, callback) {
+ACTION_P3(SetCookieWithDetailsAction, cookie_monster, cc, callback) {
   cookie_monster->SetCookieWithDetailsAsync(
-      url, name, value, domain, path, expiration_time, secure, http_only,
+      cc.url, cc.name, cc.value, cc.domain, cc.path, cc.expiration_time,
+      cc.secure, cc.http_only, cc.priority,
       callback->AsCallback());
 }
 
@@ -683,16 +711,22 @@
 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
   MockSetCookiesCallback set_cookies_callback;
 
+  CookiesInputInfo cookie_info = {
+    url_google_foo_, "A", "B", std::string(), "/foo",
+    base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
+  };
   BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction(
-      &cookie_monster(), url_google_foo_, "A", "B", std::string(), "/foo",
-      base::Time(), false, false, &set_cookies_callback));
+      &cookie_monster(), cookie_info, &set_cookies_callback));
 
   WaitForLoadCall();
 
+  CookiesInputInfo cookie_info_exp = {
+    url_google_foo_, "A", "B", std::string(), "/foo",
+    base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
+  };
   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
       SetCookieWithDetailsAction(
-          &cookie_monster(), url_google_foo_, "A", "B", std::string(), "/foo",
-          base::Time(), false, false, &set_cookies_callback));
+          &cookie_monster(), cookie_info_exp, &set_cookies_callback));
   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
       QuitCurrentMessageLoop());
 
@@ -1384,30 +1418,30 @@
 
   EXPECT_TRUE(SetCookieWithDetails(
       cm, url_google_foo_, "A", "B", std::string(), "/foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_TRUE(SetCookieWithDetails(
       cm, url_google_bar_, "C", "D", "google.izzle", "/bar", base::Time(),
-      false, true));
+      false, true, COOKIE_PRIORITY_DEFAULT));
   EXPECT_TRUE(SetCookieWithDetails(
       cm, url_google_, "E", "F", std::string(), std::string(), base::Time(),
-      true, false));
+      true, false, COOKIE_PRIORITY_DEFAULT));
 
   // Test that malformed attributes fail to set the cookie.
   EXPECT_FALSE(SetCookieWithDetails(
       cm, url_google_foo_, " A", "B", std::string(), "/foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_FALSE(SetCookieWithDetails(
       cm, url_google_foo_, "A;", "B", std::string(), "/foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_FALSE(SetCookieWithDetails(
       cm, url_google_foo_, "A=", "B", std::string(), "/foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_FALSE(SetCookieWithDetails(
       cm, url_google_foo_, "A", "B", "google.ozzzzzzle", "foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_FALSE(SetCookieWithDetails(
       cm, url_google_foo_, "A=", "B", std::string(), "foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
 
   CookieList cookies = GetAllCookiesForURL(cm, url_google_foo_);
   CookieList::iterator it = cookies.begin();
@@ -1535,11 +1569,14 @@
   SetCookieWithOptions(cm, url_google_, "setCookieWithOptions3=A", options);
 
   SetCookieWithDetails(cm, url_google_, "setCookieWithDetails1", "A",
-                       ".google.com", "/", Time(), false, false);
+                       ".google.com", "/", Time(), false, false,
+                       COOKIE_PRIORITY_DEFAULT);
   SetCookieWithDetails(cm, url_google_, "setCookieWithDetails2", "A",
-                       ".google.com", "/", Time(), false, false);
+                       ".google.com", "/", Time(), false, false,
+                       COOKIE_PRIORITY_DEFAULT);
   SetCookieWithDetails(cm, url_google_, "setCookieWithDetails3", "A",
-                       ".google.com", "/", Time(), false, false);
+                       ".google.com", "/", Time(), false, false,
+                       COOKIE_PRIORITY_DEFAULT);
 
   // Now we check
   CookieList cookie_list(GetAllCookies(cm));
@@ -1597,24 +1634,15 @@
   base::Time new_access_time;
   base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
 
-  struct CookiesInputInfo {
-    std::string gurl;
-    std::string name;
-    std::string value;
-    std::string domain;
-    std::string path;
-    base::Time expires;
-    bool secure;
-    bool http_only;
-  };
   const CookiesInputInfo input_info[] = {
-    {"http://a.b.google.com", "a", "1", "", "/path/to/cookie", expires,
-     false, false},
-    {"https://www.google.com", "b", "2", ".google.com", "/path/from/cookie",
-     expires + TimeDelta::FromSeconds(10), true, true},
-    {"https://google.com", "c", "3", "", "/another/path/to/cookie",
+    {GURL("http://a.b.google.com"), "a", "1", "", "/path/to/cookie", expires,
+     false, false, COOKIE_PRIORITY_DEFAULT},
+    {GURL("https://www.google.com"), "b", "2", ".google.com",
+     "/path/from/cookie", expires + TimeDelta::FromSeconds(10),
+     true, true, COOKIE_PRIORITY_DEFAULT},
+    {GURL("https://google.com"), "c", "3", "", "/another/path/to/cookie",
      base::Time::Now() + base::TimeDelta::FromSeconds(100),
-     true, false}
+     true, false, COOKIE_PRIORITY_DEFAULT}
   };
   const int INPUT_DELETE = 1;
 
@@ -1623,13 +1651,13 @@
     scoped_refptr<CookieMonster> cmout(new CookieMonster(store, NULL));
     for (const CookiesInputInfo* p = input_info;
          p < &input_info[ARRAYSIZE_UNSAFE(input_info)]; p++) {
-      EXPECT_TRUE(SetCookieWithDetails(cmout, GURL(p->gurl), p->name, p->value,
-                                       p->domain, p->path, p->expires,
-                                       p->secure, p->http_only));
+      EXPECT_TRUE(SetCookieWithDetails(cmout, p->url, p->name, p->value,
+                                       p->domain, p->path, p->expiration_time,
+                                       p->secure, p->http_only, p->priority));
     }
-    DeleteCookie(cmout, GURL(std::string(input_info[INPUT_DELETE].gurl) +
-                             input_info[INPUT_DELETE].path),
-                 input_info[INPUT_DELETE].name);
+    GURL del_url(input_info[INPUT_DELETE].url.Resolve(
+                     input_info[INPUT_DELETE].path).spec());
+    DeleteCookie(cmout, del_url, input_info[INPUT_DELETE].name);
   }
 
   // Create a new cookie monster and make sure that everything is correct
@@ -1647,14 +1675,14 @@
 
       EXPECT_EQ(input->name, output->Name());
       EXPECT_EQ(input->value, output->Value());
-      EXPECT_EQ(GURL(input->gurl).host(), output->Domain());
+      EXPECT_EQ(input->url.host(), output->Domain());
       EXPECT_EQ(input->path, output->Path());
       EXPECT_LE(current.ToInternalValue(),
                 output->CreationDate().ToInternalValue());
       EXPECT_EQ(input->secure, output->IsSecure());
       EXPECT_EQ(input->http_only, output->IsHttpOnly());
       EXPECT_TRUE(output->IsPersistent());
-      EXPECT_EQ(input->expires.ToInternalValue(),
+      EXPECT_EQ(input->expiration_time.ToInternalValue(),
                 output->ExpiryDate().ToInternalValue());
     }
   }
@@ -1938,7 +1966,7 @@
   ASSERT_TRUE(SetCookieWithDetails(
       cm, GURL("http://fake.a.url"), "a", "b", "a.url", "/",
       base::Time::Now() + base::TimeDelta::FromMinutes(59),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
 
   scoped_ptr<base::HistogramSamples> samples2(
       expired_histogram->SnapshotSamples());
@@ -1995,8 +2023,10 @@
     base::Time expiration_time = base::Time();
     bool secure = false;
     bool http_only = false;
+    CookiePriority priority = COOKIE_PRIORITY_DEFAULT;
     cm->SetCookieWithDetailsAsync(
         url, name, value, domain, path, expiration_time, secure, http_only,
+        priority,
         base::Bind(&SetCookieCallback::Run, base::Unretained(callback)));
   }
 
@@ -2115,7 +2145,7 @@
   EXPECT_TRUE(SetCookieWithDetails(
       cm, url_google_foo_,
       "A", "B", std::string(), "/foo", base::Time(),
-      false, false));
+      false, false, COOKIE_PRIORITY_DEFAULT));
   SetCookieCallback callback(&other_thread_);
   base::Closure task = base::Bind(
       &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask,
@@ -2126,7 +2156,6 @@
   EXPECT_TRUE(callback.result());
 }
 
-
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
   CookieOptions options;
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index ecb8712..8d382152 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -55,6 +55,7 @@
 const char kMaxAgeTokenName[] = "max-age";
 const char kSecureTokenName[] = "secure";
 const char kHttpOnlyTokenName[] = "httponly";
+const char kPriorityTokenName[] = "priority";
 
 const char kTerminator[] = "\n\r\0";
 const int kTerminatorLen = sizeof(kTerminator) - 1;
@@ -155,7 +156,8 @@
       expires_index_(0),
       maxage_index_(0),
       secure_index_(0),
-      httponly_index_(0) {
+      httponly_index_(0),
+      priority_index_(0) {
 
   if (cookie_line.size() > kMaxCookieSize) {
     VLOG(1) << "Not parsing cookie, too large: " << cookie_line.size();
@@ -174,6 +176,11 @@
   return !pairs_.empty();
 }
 
+CookiePriority ParsedCookie::Priority() const {
+  return (priority_index_ == 0) ? COOKIE_PRIORITY_DEFAULT :
+      StringToCookiePriority(pairs_[priority_index_].second);
+}
+
 bool ParsedCookie::SetName(const std::string& name) {
   if (!IsValidToken(name))
     return false;
@@ -216,6 +223,10 @@
   return SetBool(&httponly_index_, kHttpOnlyTokenName, is_http_only);
 }
 
+bool ParsedCookie::SetPriority(const std::string& priority) {
+  return SetString(&priority_index_, kPriorityTokenName, priority);
+}
+
 std::string ParsedCookie::ToCookieLine() const {
   std::string out;
   for (PairList::const_iterator it = pairs_.begin();
@@ -400,6 +411,8 @@
       secure_index_ = i;
     } else if (pairs_[i].first == kHttpOnlyTokenName) {
       httponly_index_ = i;
+    } else if (pairs_[i].first == kPriorityTokenName) {
+      priority_index_ = i;
     } else {
       /* some attribute we don't know or don't care about. */
     }
@@ -452,7 +465,8 @@
     return;
 
   size_t* indexes[] = { &path_index_, &domain_index_, &expires_index_,
-                        &maxage_index_, &secure_index_, &httponly_index_ };
+                        &maxage_index_, &secure_index_, &httponly_index_,
+                        &priority_index_ };
   for (size_t i = 0; i < arraysize(indexes); ++i) {
     if (*indexes[i] == index)
       *indexes[i] = 0;
diff --git a/net/cookies/parsed_cookie.h b/net/cookies/parsed_cookie.h
index 43afa4b..93b2c238 100644
--- a/net/cookies/parsed_cookie.h
+++ b/net/cookies/parsed_cookie.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "net/base/net_export.h"
+#include "net/cookies/cookie_constants.h"
 
 namespace net {
 
@@ -45,6 +46,7 @@
   const std::string& MaxAge() const { return pairs_[maxage_index_].second; }
   bool IsSecure() const { return secure_index_ != 0; }
   bool IsHttpOnly() const { return httponly_index_ != 0; }
+  CookiePriority Priority() const;
 
   // Returns the number of attributes, for example, returning 2 for:
   //   "BLAH=hah; path=/; domain=.google.com"
@@ -63,6 +65,7 @@
   bool SetMaxAge(const std::string& maxage);
   bool SetIsSecure(bool is_secure);
   bool SetIsHttpOnly(bool is_http_only);
+  bool SetPriority(const std::string& priority);
 
   // Returns the cookie description as it appears in a HTML response header.
   std::string ToCookieLine() const;
@@ -134,6 +137,7 @@
   size_t maxage_index_;
   size_t secure_index_;
   size_t httponly_index_;
+  size_t priority_index_;
 
   DISALLOW_COPY_AND_ASSIGN(ParsedCookie);
 };
diff --git a/net/cookies/parsed_cookie_unittest.cc b/net/cookies/parsed_cookie_unittest.cc
index 57de115..ad4aba6 100644
--- a/net/cookies/parsed_cookie_unittest.cc
+++ b/net/cookies/parsed_cookie_unittest.cc
@@ -4,17 +4,12 @@
 
 #include <string>
 
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/parsed_cookie.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 
-namespace {
-
-class ParsedCookieTest : public testing::Test { };
-
-}  // namespace
-
 TEST(ParsedCookieTest, TestBasic) {
   ParsedCookie pc("a=b");
   EXPECT_TRUE(pc.IsValid());
@@ -74,10 +69,11 @@
   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");
+  ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY; pRIoRitY=hIgH");
   EXPECT_TRUE(pc.IsValid());
   EXPECT_TRUE(pc.IsSecure());
   EXPECT_TRUE(pc.IsHttpOnly());
@@ -85,7 +81,8 @@
   EXPECT_EQ("/", pc.Path());
   EXPECT_EQ("", pc.Name());
   EXPECT_EQ("BLAHHH", pc.Value());
-  EXPECT_EQ(3U, pc.NumberOfAttributes());
+  EXPECT_EQ(COOKIE_PRIORITY_HIGH, pc.Priority());
+  EXPECT_EQ(4U, pc.NumberOfAttributes());
 }
 
 TEST(ParsedCookieTest, TestDoubleQuotedNameless) {
@@ -96,6 +93,7 @@
   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());
 }
 
@@ -104,6 +102,7 @@
   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());
 }
 
@@ -112,6 +111,7 @@
   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());
 }
 
@@ -122,6 +122,7 @@
   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());
 }
 
@@ -134,6 +135,7 @@
   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());
@@ -147,6 +149,7 @@
   EXPECT_FALSE(pc.HasDomain());
   EXPECT_TRUE(pc.IsSecure());
   EXPECT_TRUE(pc.IsHttpOnly());
+  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
   EXPECT_EQ(4U, pc.NumberOfAttributes());
 }
 
@@ -161,6 +164,7 @@
   EXPECT_TRUE(pc.HasExpires());
   EXPECT_TRUE(pc.HasPath());
   EXPECT_EQ("/", pc.Path());
+  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
   EXPECT_EQ(2U, pc.NumberOfAttributes());
 }
 
@@ -174,6 +178,7 @@
   EXPECT_TRUE(pc.HasExpires());
   EXPECT_TRUE(pc.HasPath());
   EXPECT_EQ("/", pc.Path());
+  EXPECT_EQ(COOKIE_PRIORITY_DEFAULT, pc.Priority());
   EXPECT_EQ(2U, pc.NumberOfAttributes());
 }
 
@@ -249,10 +254,10 @@
 TEST(ParsedCookieTest, SerializeCookieLine) {
   const char input[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D  ; "
                        "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
-                       "path=/  ;  ";
+                       "path=/  ;  priority=low  ;  ";
   const char output[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D; "
                         "expires=Sun, 18-Apr-2027 21:06:29 GMT; "
-                        "path=/";
+                        "path=/; priority=low";
   ParsedCookie pc(input);
   EXPECT_EQ(output, pc.ToCookieLine());
 }
@@ -331,9 +336,11 @@
   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",
+            "httponly; priority=HIGH",
             pc.ToCookieLine());
   EXPECT_TRUE(pc.HasDomain());
   EXPECT_TRUE(pc.HasPath());
@@ -341,6 +348,7 @@
   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"));
@@ -351,7 +359,14 @@
   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",
+            "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.
@@ -363,6 +378,7 @@
   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());
@@ -372,4 +388,38 @@
   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());
+}
+
 }  // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index f784b78..12459a5 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -306,6 +306,8 @@
         'cert/x509_util_openssl.h',
         'cookies/canonical_cookie.cc',
         'cookies/canonical_cookie.h',
+        'cookies/cookie_constants.cc',
+        'cookies/cookie_constants.h',
         'cookies/cookie_monster.cc',
         'cookies/cookie_monster.h',
         'cookies/cookie_options.h',
@@ -1464,6 +1466,7 @@
         'cert/x509_util_nss_unittest.cc',
         'cert/x509_util_openssl_unittest.cc',
         'cookies/canonical_cookie_unittest.cc',
+        'cookies/cookie_constants_unittest.cc',
         'cookies/cookie_monster_unittest.cc',
         'cookies/cookie_store_unittest.h',
         'cookies/cookie_util_unittest.cc',
@@ -2577,14 +2580,14 @@
           ],
         },
         {
-          'target_name': 'quic_unittests',                                            
-          'type': '<(gtest_target_type)',    
+          'target_name': 'quic_unittests',
+          'type': '<(gtest_target_type)',
           'dependencies': [
             '../base/base.gyp:test_support_base',
             '../testing/gmock.gyp:gmock',
             '../testing/gtest.gyp:gtest',
-            'net',                                                     
-            'quic_library',                                                      
+            'net',
+            'quic_library',
           ],
           'sources': [
             'quic/test_tools/quic_session_peer.cc',