This is a mechanical change.

Allow component installers to specify a map of installer attributes to be used in the update check requests.

This change extends the mechanism to specify "ap" in such a way that a map of name-value pairs can be returned by the component installer which need this capability.

R=waffles
BUG=599703

Review-Url: https://codereview.chromium.org/2102083002
Cr-Commit-Position: refs/heads/master@{#402632}
diff --git a/chrome/browser/component_updater/caps_installer_win.cc b/chrome/browser/component_updater/caps_installer_win.cc
index 7027442a..255cb9db 100644
--- a/chrome/browser/component_updater/caps_installer_win.cc
+++ b/chrome/browser/component_updater/caps_installer_win.cc
@@ -107,7 +107,9 @@
   // This string is shown in chrome://components.
   std::string GetName() const override { return "Chrome Crash Service"; }
 
-  std::string GetAp() const override { return std::string(); }
+  update_client::InstallerAttributes GetInstallerAttributes() const override {
+    return update_client::InstallerAttributes();
+  }
 };
 
 }  // namespace
diff --git a/chrome/browser/component_updater/ev_whitelist_component_installer.cc b/chrome/browser/component_updater/ev_whitelist_component_installer.cc
index 92becb5..9b99298 100644
--- a/chrome/browser/component_updater/ev_whitelist_component_installer.cc
+++ b/chrome/browser/component_updater/ev_whitelist_component_installer.cc
@@ -131,8 +131,9 @@
   return kEVWhitelistManifestName;
 }
 
-std::string EVWhitelistComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+EVWhitelistComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 void RegisterEVWhitelistComponent(ComponentUpdateService* cus,
diff --git a/chrome/browser/component_updater/ev_whitelist_component_installer.h b/chrome/browser/component_updater/ev_whitelist_component_installer.h
index c9ad8b55..b779fa5a 100644
--- a/chrome/browser/component_updater/ev_whitelist_component_installer.h
+++ b/chrome/browser/component_updater/ev_whitelist_component_installer.h
@@ -41,7 +41,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   static base::FilePath GetInstalledPath(const base::FilePath& base);
 
diff --git a/chrome/browser/component_updater/file_type_policies_component_installer.cc b/chrome/browser/component_updater/file_type_policies_component_installer.cc
index 8f261bc6..2843be1 100644
--- a/chrome/browser/component_updater/file_type_policies_component_installer.cc
+++ b/chrome/browser/component_updater/file_type_policies_component_installer.cc
@@ -113,8 +113,9 @@
   return kFileTypePoliciesManifestName;
 }
 
-std::string FileTypePoliciesComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+FileTypePoliciesComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 void RegisterFileTypePoliciesComponent(ComponentUpdateService* cus,
diff --git a/chrome/browser/component_updater/file_type_policies_component_installer.h b/chrome/browser/component_updater/file_type_policies_component_installer.h
index 3de2b7fd..be24251 100644
--- a/chrome/browser/component_updater/file_type_policies_component_installer.h
+++ b/chrome/browser/component_updater/file_type_policies_component_installer.h
@@ -42,7 +42,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   static base::FilePath GetInstalledPath(const base::FilePath& base);
 
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.cc b/chrome/browser/component_updater/origin_trials_component_installer.cc
index 244f8d5a..25262de 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.cc
+++ b/chrome/browser/component_updater/origin_trials_component_installer.cc
@@ -102,8 +102,9 @@
   return "Origin Trials";
 }
 
-std::string OriginTrialsComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+OriginTrialsComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 void RegisterOriginTrialsComponent(ComponentUpdateService* cus,
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.h b/chrome/browser/component_updater/origin_trials_component_installer.h
index 97fa333a..09bca82 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.h
+++ b/chrome/browser/component_updater/origin_trials_component_installer.h
@@ -39,7 +39,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   DISALLOW_COPY_AND_ASSIGN(OriginTrialsComponentInstallerTraits);
 };
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 472e25c7..94c8d59e 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -184,7 +184,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   DISALLOW_COPY_AND_ASSIGN(FlashComponentInstallerTraits);
 };
@@ -253,8 +253,9 @@
   return "pepper_flash";
 }
 
-std::string FlashComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+FlashComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
diff --git a/chrome/browser/component_updater/sth_set_component_installer.cc b/chrome/browser/component_updater/sth_set_component_installer.cc
index c4f2ba5..b6ced013 100644
--- a/chrome/browser/component_updater/sth_set_component_installer.cc
+++ b/chrome/browser/component_updater/sth_set_component_installer.cc
@@ -102,8 +102,9 @@
   return kSTHSetFetcherManifestName;
 }
 
-std::string STHSetComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+STHSetComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 void STHSetComponentInstallerTraits::LoadSTHsFromDisk(
diff --git a/chrome/browser/component_updater/sth_set_component_installer.h b/chrome/browser/component_updater/sth_set_component_installer.h
index 1279706..90aec8a 100644
--- a/chrome/browser/component_updater/sth_set_component_installer.h
+++ b/chrome/browser/component_updater/sth_set_component_installer.h
@@ -59,7 +59,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   // Reads and parses the on-disk json.
   void LoadSTHsFromDisk(const base::FilePath& sths_file_path,
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.cc b/chrome/browser/component_updater/subresource_filter_component_installer.cc
index 75d3860..3465ca95 100644
--- a/chrome/browser/component_updater/subresource_filter_component_installer.cc
+++ b/chrome/browser/component_updater/subresource_filter_component_installer.cc
@@ -91,8 +91,9 @@
   return kSubresourceFilterSetFetcherManifestName;
 }
 
-std::string SubresourceFilterComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+SubresourceFilterComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 void SubresourceFilterComponentInstallerTraits::
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.h b/chrome/browser/component_updater/subresource_filter_component_installer.h
index 6d39fc3a..86b2b45 100644
--- a/chrome/browser/component_updater/subresource_filter_component_installer.h
+++ b/chrome/browser/component_updater/subresource_filter_component_installer.h
@@ -5,6 +5,9 @@
 #ifndef CHROME_BROWSER_COMPONENT_UPDATER_SUBRESOURCE_FILTER_COMPONENT_INSTALLER_H_
 #define CHROME_BROWSER_COMPONENT_UPDATER_SUBRESOURCE_FILTER_COMPONENT_INSTALLER_H_
 
+#include <string>
+#include <vector>
+
 #include "components/component_updater/default_component_installer.h"
 
 namespace base {
@@ -39,7 +42,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   // Reads and parses the on-disk ruleset file.
   void LoadSubresourceFilterRulesFromDisk(const base::FilePath& file_path,
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
index 97f9db0..c903f115 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
@@ -260,7 +260,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   std::string crx_id_;
   std::string name_;
@@ -320,8 +320,10 @@
   return name_;
 }
 
-std::string SupervisedUserWhitelistComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+SupervisedUserWhitelistComponentInstallerTraits::GetInstallerAttributes()
+    const {
+  return update_client::InstallerAttributes();
 }
 
 class SupervisedUserWhitelistInstallerImpl
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index b5147d0728..49a0461 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -140,7 +140,9 @@
 
   std::string GetName() const override { return "Software Reporter Tool"; }
 
-  std::string GetAp() const override { return std::string(); }
+  update_client::InstallerAttributes GetInstallerAttributes() const override {
+    return update_client::InstallerAttributes();
+  }
 
   static std::string ID() {
     update_client::CrxComponent component;
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index e4f11e3..eb746092 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -260,7 +260,7 @@
   base::FilePath GetRelativeInstallDir() const override;
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
-  std::string GetAp() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
 
   // Checks and updates CDM adapter if necessary to make sure the latest CDM
   // adapter is always used.
@@ -335,8 +335,9 @@
   return kWidevineCdmDisplayName;
 }
 
-std::string WidevineCdmComponentInstallerTraits::GetAp() const {
-  return std::string();
+update_client::InstallerAttributes
+WidevineCdmComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
 }
 
 static bool HasValidAdapter(const base::FilePath& adapter_version_path,
diff --git a/components/component_updater/default_component_installer.cc b/components/component_updater/default_component_installer.cc
index 111a45f5..fa071a2 100644
--- a/components/component_updater/default_component_installer.cc
+++ b/components/component_updater/default_component_installer.cc
@@ -332,7 +332,7 @@
     crx.version = current_version_;
     crx.fingerprint = current_fingerprint_;
     crx.name = installer_traits_->GetName();
-    crx.ap = installer_traits_->GetAp();
+    crx.installer_attributes = installer_traits_->GetInstallerAttributes();
     crx.requires_network_encryption =
         installer_traits_->RequiresNetworkEncryption();
     if (!cus->RegisterComponent(crx)) {
diff --git a/components/component_updater/default_component_installer.h b/components/component_updater/default_component_installer.h
index f728b43..8819c29 100644
--- a/components/component_updater/default_component_installer.h
+++ b/components/component_updater/default_component_installer.h
@@ -86,11 +86,15 @@
   // Returns the human-readable name of the component.
   virtual std::string GetName() const = 0;
 
-  // Returns the additional parameters to be used in the update checks for
-  // this component. A compatible server may use this attribute to negotiate
-  // special update rules when issuing an update response.
-  // The current implementation restricts ap to ^([-+_=a-zA-Z0-9]{0,256})$
-  virtual std::string GetAp() const = 0;
+  // Returns a container of name-value pairs representing arbitrary,
+  // installer-defined metadata.
+  // The installer metadata may be used in the update checks for this component.
+  // A compatible server may use these attributes to negotiate special update
+  // rules when issuing an update response.
+  // Valid values for the name part of an attribute match
+  // ^[-_a-zA-Z0-9]{1,256}$ and valid values the value part of an attribute
+  // match ^[-.,;+_=a-zA-Z0-9]{0,256}$ .
+  virtual update_client::InstallerAttributes GetInstallerAttributes() const = 0;
 };
 
 // A DefaultComponentInstaller is intended to be final, and not derived from.
diff --git a/components/component_updater/default_component_installer_unittest.cc b/components/component_updater/default_component_installer_unittest.cc
index 63038f07..184ef2b 100644
--- a/components/component_updater/default_component_installer_unittest.cc
+++ b/components/component_updater/default_component_installer_unittest.cc
@@ -42,7 +42,7 @@
 
 class MockUpdateClient : public UpdateClient {
  public:
-  MockUpdateClient() {};
+  MockUpdateClient() {}
   MOCK_METHOD1(AddObserver, void(Observer* observer));
   MOCK_METHOD1(RemoveObserver, void(Observer* observer));
   MOCK_METHOD3(Install,
@@ -61,7 +61,7 @@
                void(const std::string& id, const Version& version, int reason));
 
  private:
-  ~MockUpdateClient() override {};
+  ~MockUpdateClient() override {}
 };
 
 class FakeInstallerTraits : public ComponentInstallerTraits {
@@ -95,7 +95,12 @@
 
   std::string GetName() const override { return "fake name"; }
 
-  std::string GetAp() const override { return "fake-ap"; }
+  update_client::InstallerAttributes GetInstallerAttributes() const override {
+    update_client::InstallerAttributes installer_attributes;
+    installer_attributes["ap"] = "fake-ap";
+    installer_attributes["is-enterprise"] = "1";
+    return installer_attributes;
+  }
 
  private:
   static void GetPkHash(std::vector<uint8_t>* hash) {
@@ -203,13 +208,18 @@
   CrxUpdateItem item;
   EXPECT_TRUE(component_updater()->GetComponentDetails(id, &item));
   const CrxComponent& component(item.component);
+
+  update_client::InstallerAttributes expected_attrs;
+  expected_attrs["ap"] = "fake-ap";
+  expected_attrs["is-enterprise"] = "1";
+
   EXPECT_EQ(
       std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
       component.pk_hash);
   EXPECT_EQ(base::Version("0.0.0.0"), component.version);
   EXPECT_TRUE(component.fingerprint.empty());
   EXPECT_STREQ("fake name", component.name.c_str());
-  EXPECT_STREQ("fake-ap", component.ap.c_str());
+  EXPECT_EQ(expected_attrs, component.installer_attributes);
   EXPECT_TRUE(component.requires_network_encryption);
 }
 
diff --git a/components/update_client/update_checker.cc b/components/update_client/update_checker.cc
index 7ffcecc..6080b13a 100644
--- a/components/update_client/update_checker.cc
+++ b/components/update_client/update_checker.cc
@@ -22,6 +22,7 @@
 #include "components/update_client/crx_update_item.h"
 #include "components/update_client/persisted_data.h"
 #include "components/update_client/request_sender.h"
+#include "components/update_client/update_client.h"
 #include "components/update_client/utils.h"
 #include "url/gurl.h"
 
@@ -34,9 +35,15 @@
   return IsValidBrand(brand) ? brand : std::string("");
 }
 
-// Returns a sanitized version of the |ap| or an empty string otherwise.
-std::string SanitizeAp(const std::string& ap) {
-  return IsValidAp(ap) ? ap : std::string();
+// Filters invalid attributes from |installer_attributes|.
+update_client::InstallerAttributes SanitizeInstallerAttributes(
+    const update_client::InstallerAttributes& installer_attributes) {
+  update_client::InstallerAttributes sanitized_attrs;
+  for (const auto& attr : installer_attributes) {
+    if (IsValidInstallerAttribute(attr))
+      sanitized_attrs.insert(attr);
+  }
+  return sanitized_attrs;
 }
 
 // Returns true if at least one item requires network encryption.
@@ -70,7 +77,8 @@
   std::string app_elements;
   for (size_t i = 0; i != items.size(); ++i) {
     const CrxUpdateItem* item = items[i];
-    const std::string ap(SanitizeAp(item->component.ap));
+    const update_client::InstallerAttributes installer_attributes(
+        SanitizeInstallerAttributes(item->component.installer_attributes));
     std::string app("<app ");
     base::StringAppendF(&app, "appid=\"%s\" version=\"%s\"", item->id.c_str(),
                         item->component.version.GetString().c_str());
@@ -78,8 +86,11 @@
       base::StringAppendF(&app, " brand=\"%s\"", brand.c_str());
     if (item->on_demand)
       base::StringAppendF(&app, " installsource=\"ondemand\"");
-    if (!ap.empty())
-      base::StringAppendF(&app, " ap=\"%s\"", ap.c_str());
+
+    for (const auto& attr : installer_attributes)
+      base::StringAppendF(&app, " %s=\"%s\"", attr.first.c_str(),
+                          attr.second.c_str());
+
     base::StringAppendF(&app, ">");
     base::StringAppendF(&app, "<updatecheck />");
     base::StringAppendF(&app, "<ping rd=\"%d\" ping_freshness=\"%s\" />",
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 9e528dc4..8bac5ea1 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -170,7 +170,7 @@
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
 
   CrxUpdateItem item(BuildCrxUpdateItem());
-  item.component.ap = "some_ap";
+  item.component.installer_attributes["ap"] = "some_ap";
   std::vector<CrxUpdateItem*> items_to_check;
   items_to_check.push_back(&item);
 
@@ -220,7 +220,8 @@
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
 
   CrxUpdateItem item(BuildCrxUpdateItem());
-  item.component.ap = std::string(257, 'a');  // Too long.
+  // Make "ap" too long.
+  item.component.installer_attributes["ap"] = std::string(257, 'a');
   std::vector<CrxUpdateItem*> items_to_check;
   items_to_check.push_back(&item);
 
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index 0c0e42d..5f1a8eb 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -182,6 +183,10 @@
   virtual ~CrxInstaller() {}
 };
 
+// A dictionary of installer-specific, arbitrary name-value pairs, which
+// may be used in the update checks requests.
+using InstallerAttributes = std::map<std::string, std::string>;
+
 // TODO(sorin): this structure will be refactored soon.
 struct CrxComponent {
   CrxComponent();
@@ -198,7 +203,12 @@
 
   std::string fingerprint;  // Optional.
   std::string name;         // Optional.
-  std::string ap;           // Optional. Must match ^[-+_=a-zA-Z0-9]{0,256}$
+
+  // Optional.
+  // Valid values for the name part of an attribute match
+  // ^[-_a-zA-Z0-9]{1,256}$ and valid values the value part of an attribute
+  // match ^[-.,;+_=a-zA-Z0-9]{0,256}$ .
+  InstallerAttributes installer_attributes;
 
   // Specifies that the CRX can be background-downloaded in some cases.
   // The default for this value is |true|.
diff --git a/components/update_client/utils.cc b/components/update_client/utils.cc
index 90bbc119..717984d 100644
--- a/components/update_client/utils.cc
+++ b/components/update_client/utils.cc
@@ -239,23 +239,42 @@
          }) == brand.end();
 }
 
-bool IsValidAp(const std::string& ap) {
-  const size_t kMaxApSize = 256;
-  if (ap.size() > kMaxApSize)
+// Helper function.
+// Returns true if |part| matches the expression
+// ^[<special_chars>a-zA-Z0-9]{min_length,max_length}$
+bool IsValidInstallerAttributePart(const std::string& part,
+                                   const std::string& special_chars,
+                                   size_t min_length,
+                                   size_t max_length) {
+  if (part.size() < min_length || part.size() > max_length)
     return false;
 
-  return std::find_if_not(ap.begin(), ap.end(), [](char ch) {
+  return std::find_if_not(part.begin(), part.end(), [&special_chars](char ch) {
            if (base::IsAsciiAlpha(ch) || base::IsAsciiDigit(ch))
              return true;
 
-           const char kSpecialChars[] = "+-_=";
-           for (auto c : kSpecialChars) {
+           for (auto c : special_chars) {
              if (c == ch)
                return true;
            }
 
            return false;
-         }) == ap.end();
+         }) == part.end();
+}
+
+// Returns true if the |name| parameter matches ^[-_a-zA-Z0-9]{1,256}$ .
+bool IsValidInstallerAttributeName(const std::string& name) {
+  return IsValidInstallerAttributePart(name, "-_", 1, 256);
+}
+
+// Returns true if the |value| parameter matches ^[-.,;+_=a-zA-Z0-9]{0,256}$ .
+bool IsValidInstallerAttributeValue(const std::string& value) {
+  return IsValidInstallerAttributePart(value, "-.,;+_=", 0, 256);
+}
+
+bool IsValidInstallerAttribute(const InstallerAttribute& attr) {
+  return IsValidInstallerAttributeName(attr.first) &&
+         IsValidInstallerAttributeValue(attr.second);
 }
 
 void RemoveUnsecureUrls(std::vector<GURL>* urls) {
diff --git a/components/update_client/utils.h b/components/update_client/utils.h
index 2306cf2a..f800b4f 100644
--- a/components/update_client/utils.h
+++ b/components/update_client/utils.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 
@@ -28,6 +29,11 @@
 struct CrxComponent;
 struct CrxUpdateItem;
 
+// Defines a name-value pair that represents an installer attribute.
+// Installer attributes are component-specific metadata, which may be serialized
+// in an update check request.
+using InstallerAttribute = std::pair<std::string, std::string>;
+
 // An update protocol request starts with a common preamble which includes
 // version and platform information for Chrome and the operating system,
 // followed by a request body, which is the actual payload of the request.
@@ -99,8 +105,10 @@
 // Returns true if the |brand| parameter matches ^[a-zA-Z]{4}?$ .
 bool IsValidBrand(const std::string& brand);
 
-// Returns true if the |ap| parameter matches ^[-+_=a-zA-Z0-9]{0,256}$ .
-bool IsValidAp(const std::string& ap);
+// Returns true if the name part of the |attr| parameter matches
+// ^[-_a-zA-Z0-9]{1,256}$ and the value part of the |attr| parameter
+// matches ^[-.,;+_=a-zA-Z0-9]{0,256}$ .
+bool IsValidInstallerAttribute(const InstallerAttribute& attr);
 
 // Removes the unsecure urls in the |urls| parameter.
 void RemoveUnsecureUrls(std::vector<GURL>* urls);
diff --git a/components/update_client/utils_unittest.cc b/components/update_client/utils_unittest.cc
index bd92460..5865419e 100644
--- a/components/update_client/utils_unittest.cc
+++ b/components/update_client/utils_unittest.cc
@@ -75,33 +75,59 @@
   EXPECT_FALSE(IsValidBrand(std::string("T ES")));   // Contains white space.
   EXPECT_FALSE(IsValidBrand(std::string("<TE")));    // Has <.
   EXPECT_FALSE(IsValidBrand(std::string("TE>")));    // Has >.
-  EXPECT_FALSE(IsValidAp(std::string("\"")));        // Has "
-  EXPECT_FALSE(IsValidAp(std::string("\\")));        // Has backslash.
+  EXPECT_FALSE(IsValidBrand(std::string("\"")));     // Has "
+  EXPECT_FALSE(IsValidBrand(std::string("\\")));     // Has backslash.
   EXPECT_FALSE(IsValidBrand(std::string("\xaa")));   // Has non-ASCII char.
 }
 
-// Tests that the ap matches ^[-+_=a-zA-Z0-9]{0,256}$
-TEST(UpdateClientUtils, IsValidAp) {
-  EXPECT_TRUE(IsValidAp(std::string("a=1")));
-  EXPECT_TRUE(IsValidAp(std::string("")));
-  EXPECT_TRUE(IsValidAp(std::string("A")));
-  EXPECT_TRUE(IsValidAp(std::string("Z")));
-  EXPECT_TRUE(IsValidAp(std::string("a")));
-  EXPECT_TRUE(IsValidAp(std::string("z")));
-  EXPECT_TRUE(IsValidAp(std::string("0")));
-  EXPECT_TRUE(IsValidAp(std::string("9")));
-  EXPECT_TRUE(IsValidAp(std::string(256, 'a')));
-  EXPECT_TRUE(IsValidAp(std::string("-+_=")));
+// Tests that the name of an InstallerAttribute matches ^[-_=a-zA-Z0-9]{1,256}$
+TEST(UpdateClientUtils, IsValidInstallerAttributeName) {
+  // Test the length boundaries.
+  EXPECT_FALSE(IsValidInstallerAttribute(
+      make_pair(std::string(0, 'a'), std::string("value"))));
+  EXPECT_TRUE(IsValidInstallerAttribute(
+      make_pair(std::string(1, 'a'), std::string("value"))));
+  EXPECT_TRUE(IsValidInstallerAttribute(
+      make_pair(std::string(256, 'a'), std::string("value"))));
+  EXPECT_FALSE(IsValidInstallerAttribute(
+      make_pair(std::string(257, 'a'), std::string("value"))));
 
-  EXPECT_FALSE(IsValidAp(std::string(257, 'a')));  // Too long.
-  EXPECT_FALSE(IsValidAp(std::string(" ap")));     // Begins with white space.
-  EXPECT_FALSE(IsValidAp(std::string("ap ")));     // Ends with white space.
-  EXPECT_FALSE(IsValidAp(std::string("a p")));     // Contains white space.
-  EXPECT_FALSE(IsValidAp(std::string("<ap")));     // Has <.
-  EXPECT_FALSE(IsValidAp(std::string("ap>")));     // Has >.
-  EXPECT_FALSE(IsValidAp(std::string("\"")));      // Has "
-  EXPECT_FALSE(IsValidAp(std::string("\\")));      // Has backspace.
-  EXPECT_FALSE(IsValidAp(std::string("\xaa")));    // Has non-ASCII char.
+  const char* const valid_names[] = {"A", "Z", "a", "a-b", "A_B",
+                                     "z", "0", "9", "-_"};
+  for (const auto& name : valid_names)
+    EXPECT_TRUE(IsValidInstallerAttribute(
+        make_pair(std::string(name), std::string("value"))));
+
+  const char* const invalid_names[] = {
+      "",   "a=1", " name", "name ", "na me", "<name", "name>",
+      "\"", "\\",  "\xaa",  ".",     ",",     ";",     "+"};
+  for (const auto& name : invalid_names)
+    EXPECT_FALSE(IsValidInstallerAttribute(
+        make_pair(std::string(name), std::string("value"))));
+}
+
+// Tests that the value of an InstallerAttribute matches
+// ^[-.,;+_=a-zA-Z0-9]{0,256}$
+TEST(UpdateClientUtils, IsValidInstallerAttributeValue) {
+  // Test the length boundaries.
+  EXPECT_TRUE(IsValidInstallerAttribute(
+      make_pair(std::string("name"), std::string(0, 'a'))));
+  EXPECT_TRUE(IsValidInstallerAttribute(
+      make_pair(std::string("name"), std::string(256, 'a'))));
+  EXPECT_FALSE(IsValidInstallerAttribute(
+      make_pair(std::string("name"), std::string(257, 'a'))));
+
+  const char* const valid_values[] = {"",  "a=1", "A", "Z",      "a",
+                                      "z", "0",   "9", "-.,;+_="};
+  for (const auto& value : valid_values)
+    EXPECT_TRUE(IsValidInstallerAttribute(
+        make_pair(std::string("name"), std::string(value))));
+
+  const char* const invalid_values[] = {" ap", "ap ", "a p", "<ap",
+                                        "ap>", "\"",  "\\",  "\xaa"};
+  for (const auto& value : invalid_values)
+    EXPECT_FALSE(IsValidInstallerAttribute(
+        make_pair(std::string("name"), std::string(value))));
 }
 
 TEST(UpdateClientUtils, RemoveUnsecureUrls) {