Merge from Chromium at DEPS revision 225410
This commit was generated by merge_to_master.py.
Change-Id: Ifa1539ca216abb163295ee7a77f81bb67f52e178
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index 311aa3f..2775d78 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -151,6 +151,7 @@
kWebRequest,
kWebRequestBlocking,
kWebRequestInternal,
+ kWebrtcLoggingPrivate,
kWebstorePrivate,
kWebView,
kSystemCpu,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index f57c58e..308aaef 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -234,6 +234,8 @@
{ APIPermission::kEnterprisePlatformKeysPrivate,
"enterprise.platformKeysPrivate",
APIPermissionInfo::kFlagCannotBeOptional },
+ { APIPermission::kWebrtcLoggingPrivate, "webrtcLoggingPrivate",
+ APIPermissionInfo::kFlagCannotBeOptional },
// Full url access permissions.
{ APIPermission::kDebugger, "debugger",
diff --git a/chrome/common/extensions/permissions/permission_message.cc b/chrome/common/extensions/permissions/permission_message.cc
index b792ae9..006e91a 100644
--- a/chrome/common/extensions/permissions/permission_message.cc
+++ b/chrome/common/extensions/permissions/permission_message.cc
@@ -45,17 +45,27 @@
default:
message_id = kHosts4OrMore;
- message = l10n_util::GetStringFUTF16(
- IDS_EXTENSION_PROMPT_WARNING_HOSTS,
- base::IntToString16(host_list.size()));
+ const int kRetainedFilesMessageIDs[6] = {
+ IDS_EXTENSION_PROMPT_WARNING_HOSTS_DEFAULT,
+ IDS_EXTENSION_PROMPT_WARNING_HOST_SINGULAR,
+ IDS_EXTENSION_PROMPT_WARNING_HOSTS_ZERO,
+ IDS_EXTENSION_PROMPT_WARNING_HOSTS_TWO,
+ IDS_EXTENSION_PROMPT_WARNING_HOSTS_FEW,
+ IDS_EXTENSION_PROMPT_WARNING_HOSTS_MANY,
+ };
+ std::vector<int> message_ids;
+ for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) {
+ message_ids.push_back(kRetainedFilesMessageIDs[i]);
+ }
+ message = l10n_util::GetPluralStringFUTF16(message_ids, host_list.size());
- for (size_t i = 0; i < host_list.size(); ++i) {
- if (i > 0)
- details += ASCIIToUTF16("\n");
- details += l10n_util::GetStringFUTF16(
- IDS_EXTENSION_PROMPT_WARNING_HOST_LIST_ENTRY,
- UTF8ToUTF16(host_list[i]));
- }
+ for (size_t i = 0; i < host_list.size(); ++i) {
+ if (i > 0)
+ details += ASCIIToUTF16("\n");
+ details += l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_HOST_LIST_ENTRY,
+ UTF8ToUTF16(host_list[i]));
+ }
}
return PermissionMessage(message_id, message, details);
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 9991ecc..cd4a2e1 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -729,6 +729,7 @@
skip.insert(APIPermission::kVirtualKeyboardPrivate);
skip.insert(APIPermission::kWallpaperPrivate);
skip.insert(APIPermission::kWebRequestInternal);
+ skip.insert(APIPermission::kWebrtcLoggingPrivate);
skip.insert(APIPermission::kWebstorePrivate);
// Warned as part of host permissions.
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index d1b70e9..1fc56c5 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -175,7 +175,7 @@
PermissionsData::GetPermissionMessageDetailsStrings(extension.get());
ASSERT_EQ(1u, warnings.size());
ASSERT_EQ(1u, warnings_details.size());
- EXPECT_EQ("Access your data on 5 website(s)", UTF16ToUTF8(warnings[0]));
+ EXPECT_EQ("Access your data on 5 websites", UTF16ToUTF8(warnings[0]));
EXPECT_EQ("- www.a.com\n- www.b.com\n- www.c.com\n- www.d.com\n- www.e.com",
UTF16ToUTF8(warnings_details[0]));
}
diff --git a/chrome/common/extensions/permissions/socket_permission.cc b/chrome/common/extensions/permissions/socket_permission.cc
index ebf7205..9f2c35c 100644
--- a/chrome/common/extensions/permissions/socket_permission.cc
+++ b/chrome/common/extensions/permissions/socket_permission.cc
@@ -37,8 +37,8 @@
bool SocketPermission::AddAnyHostMessage(PermissionMessages& messages) const {
std::set<SocketPermissionData>::const_iterator i;
for (i = data_set_.begin(); i != data_set_.end(); ++i) {
- if (i->IsAddressBoundType() &&
- i->GetHostType() == SocketPermissionData::ANY_HOST) {
+ if (i->entry().IsAddressBoundType() &&
+ i->entry().GetHostType() == SocketPermissionEntry::ANY_HOST) {
messages.push_back(PermissionMessage(
PermissionMessage::kSocketAnyHost,
l10n_util::GetStringUTF16(
@@ -54,8 +54,8 @@
std::set<string16> domains;
std::set<SocketPermissionData>::const_iterator i;
for (i = data_set_.begin(); i != data_set_.end(); ++i) {
- if (i->GetHostType() == SocketPermissionData::HOSTS_IN_DOMAINS)
- domains.insert(UTF8ToUTF16(i->GetHost()));
+ if (i->entry().GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
+ domains.insert(UTF8ToUTF16(i->entry().pattern().host));
}
if (!domains.empty()) {
int id = (domains.size() == 1) ?
@@ -76,8 +76,8 @@
std::set<string16> hostnames;
std::set<SocketPermissionData>::const_iterator i;
for (i = data_set_.begin(); i != data_set_.end(); ++i) {
- if (i->GetHostType() == SocketPermissionData::SPECIFIC_HOSTS)
- hostnames.insert(UTF8ToUTF16(i->GetHost()));
+ if (i->entry().GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
+ hostnames.insert(UTF8ToUTF16(i->entry().pattern().host));
}
if (!hostnames.empty()) {
int id = (hostnames.size() == 1) ?
@@ -97,7 +97,8 @@
PermissionMessages& messages) const {
std::set<SocketPermissionData>::const_iterator i;
for (i = data_set_.begin(); i != data_set_.end(); ++i) {
- if (i->pattern().type == content::SocketPermissionRequest::NETWORK_STATE) {
+ if (i->entry().pattern().type ==
+ content::SocketPermissionRequest::NETWORK_STATE) {
messages.push_back(PermissionMessage(
PermissionMessage::kNetworkState,
l10n_util::GetStringUTF16(
diff --git a/chrome/common/extensions/permissions/socket_permission_data.cc b/chrome/common/extensions/permissions/socket_permission_data.cc
index fc7908e..e87fd84 100644
--- a/chrome/common/extensions/permissions/socket_permission_data.cc
+++ b/chrome/common/extensions/permissions/socket_permission_data.cc
@@ -23,8 +23,6 @@
using extensions::SocketPermissionData;
const char kColon = ':';
-const char kDot = '.';
-const char kWildcard[] = "*";
const char kInvalid[] = "invalid";
const char kTCPConnect[] = "tcp-connect";
const char kTCPListen[] = "tcp-listen";
@@ -34,8 +32,6 @@
const char kResolveHost[] = "resolve-host";
const char kResolveProxy[] = "resolve-proxy";
const char kNetworkState[] = "network-state";
-const int kWildcardPortNumber = 0;
-const int kInvalidPort = -1;
SocketPermissionRequest::OperationType StringToType(const std::string& s) {
if (s == kTCPConnect)
@@ -80,52 +76,20 @@
}
}
-bool StartsOrEndsWithWhitespace(const std::string& str) {
- if (str.find_first_not_of(kWhitespaceASCII) != 0)
- return true;
- if (str.find_last_not_of(kWhitespaceASCII) != str.length() - 1)
- return true;
- return false;
-}
-
} // namespace
namespace extensions {
-SocketPermissionData::SocketPermissionData()
- : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort) {
- Reset();
-}
+SocketPermissionData::SocketPermissionData() { }
-SocketPermissionData::~SocketPermissionData() {
-}
+SocketPermissionData::~SocketPermissionData() { }
bool SocketPermissionData::operator<(const SocketPermissionData& rhs) const {
- if (pattern_.type < rhs.pattern_.type)
- return true;
- if (pattern_.type > rhs.pattern_.type)
- return false;
-
- if (pattern_.host < rhs.pattern_.host)
- return true;
- if (pattern_.host > rhs.pattern_.host)
- return false;
-
- if (match_subdomains_ < rhs.match_subdomains_)
- return true;
- if (match_subdomains_ > rhs.match_subdomains_)
- return false;
-
- if (pattern_.port < rhs.pattern_.port)
- return true;
- return false;
+ return entry_ < rhs.entry_;
}
bool SocketPermissionData::operator==(const SocketPermissionData& rhs) const {
- return (pattern_.type == rhs.pattern_.type) &&
- (pattern_.host == rhs.pattern_.host) &&
- (match_subdomains_ == rhs.match_subdomains_) &&
- (pattern_.port == rhs.pattern_.port);
+ return entry_ == rhs.entry_;
}
bool SocketPermissionData::Check(
@@ -136,41 +100,7 @@
*static_cast<const SocketPermission::CheckParam*>(param);
const SocketPermissionRequest &request = specific_param.request;
- if (pattern_.type != request.type)
- return false;
-
- std::string lhost = StringToLowerASCII(request.host);
- if (pattern_.host != lhost) {
- if (!match_subdomains_)
- return false;
-
- if (!pattern_.host.empty()) {
- // Do not wildcard part of IP address.
- url_parse::Component component(0, lhost.length());
- url_canon::RawCanonOutputT<char, 128> ignored_output;
- url_canon::CanonHostInfo host_info;
- url_canon::CanonicalizeIPAddress(lhost.c_str(), component,
- &ignored_output, &host_info);
- if (host_info.IsIPAddress())
- return false;
-
- // host should equal one or more chars + "." + host_.
- int i = lhost.length() - pattern_.host.length();
- if (i < 2)
- return false;
-
- if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
- return false;
-
- if (lhost[i - 1] != kDot)
- return false;
- }
- }
-
- if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
- return false;
-
- return true;
+ return entry_.Check(request);
}
scoped_ptr<base::Value> SocketPermissionData::ToValue() const {
@@ -185,95 +115,27 @@
return Parse(spec);
}
-bool SocketPermissionData::IsAddressBoundType() const {
- return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
- pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
- pattern_.type == SocketPermissionRequest::UDP_BIND ||
- pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
-}
-
-SocketPermissionData::HostType SocketPermissionData::GetHostType() const {
- return pattern_.host.empty() ? SocketPermissionData::ANY_HOST :
- match_subdomains_ ? SocketPermissionData::HOSTS_IN_DOMAINS :
- SocketPermissionData::SPECIFIC_HOSTS;
-}
-
-const std::string SocketPermissionData::GetHost() const {
- return pattern_.host;
-}
-
-content::SocketPermissionRequest& SocketPermissionData::pattern() {
- // Clear the spec because the caller could mutate |this|.
- spec_.clear();
- return pattern_;
-}
-
-bool& SocketPermissionData::match_subdomains() {
- // Clear the spec because the caller could mutate |this|.
- spec_.clear();
- return match_subdomains_;
+SocketPermissionEntry& SocketPermissionData::entry() {
+ // Clear the spec because the caller could mutate |this|.
+ spec_.clear();
+ return entry_;
}
// TODO(ikarienator): Rewrite this method to support IPv6.
bool SocketPermissionData::Parse(const std::string& permission) {
- do {
- pattern_.host.clear();
- match_subdomains_ = true;
- pattern_.port = kWildcardPortNumber;
- spec_.clear();
-
- std::vector<std::string> tokens;
- base::SplitStringDontTrim(permission, kColon, &tokens);
-
- if (tokens.empty() || tokens.size() > 3)
- break;
-
- pattern_.type = StringToType(tokens[0]);
- if (pattern_.type == SocketPermissionRequest::NONE)
- break;
-
- if (tokens.size() == 1)
- return true;
-
- // Return an error if address is specified for permissions that don't
- // need it (such as 'resolve-host').
- if (!IsAddressBoundType())
- break;
-
- pattern_.host = tokens[1];
- if (!pattern_.host.empty()) {
- if (StartsOrEndsWithWhitespace(pattern_.host))
- break;
- pattern_.host = StringToLowerASCII(pattern_.host);
-
- // The first component can optionally be '*' to match all subdomains.
- std::vector<std::string> host_components;
- base::SplitString(pattern_.host, kDot, &host_components);
- DCHECK(!host_components.empty());
-
- if (host_components[0] == kWildcard || host_components[0].empty()) {
- host_components.erase(host_components.begin(),
- host_components.begin() + 1);
- } else {
- match_subdomains_ = false;
- }
- pattern_.host = JoinString(host_components, kDot);
- }
-
- if (tokens.size() == 2 || tokens[2].empty() || tokens[2] == kWildcard)
- return true;
-
- if (StartsOrEndsWithWhitespace(tokens[2]))
- break;
-
- if (!base::StringToInt(tokens[2], &pattern_.port) ||
- pattern_.port < 1 || pattern_.port > 65535)
- break;
- return true;
- } while (false);
-
Reset();
- return false;
+
+ std::vector<std::string> tokens;
+ base::SplitStringDontTrim(permission, kColon, &tokens);
+ if (tokens.empty())
+ return false;
+
+ SocketPermissionRequest::OperationType type = StringToType(tokens[0]);
+ if (type == SocketPermissionRequest::NONE)
+ return false;
+
+ tokens.erase(tokens.begin());
+ return SocketPermissionEntry::ParseHostPattern(type, tokens, &entry_);
}
const std::string& SocketPermissionData::GetAsString() const {
@@ -281,32 +143,16 @@
return spec_;
spec_.reserve(64);
- spec_.append(TypeToString(pattern_.type));
-
- if (!IsAddressBoundType())
- return spec_;
-
- if (match_subdomains_) {
- spec_.append(1, kColon).append(kWildcard);
- if (!pattern_.host.empty())
- spec_.append(1, kDot).append(pattern_.host);
- } else {
- spec_.append(1, kColon).append(pattern_.host);
+ spec_.append(TypeToString(entry_.pattern().type));
+ std::string pattern = entry_.GetHostPatternAsString();
+ if (!pattern.empty()) {
+ spec_.append(1, kColon).append(pattern);
}
-
- if (pattern_.port == kWildcardPortNumber)
- spec_.append(1, kColon).append(kWildcard);
- else
- spec_.append(1, kColon).append(base::IntToString(pattern_.port));
-
return spec_;
}
void SocketPermissionData::Reset() {
- pattern_.type = SocketPermissionRequest::NONE;
- pattern_.host.clear();
- match_subdomains_ = false;
- pattern_.port = kInvalidPort;
+ entry_ = SocketPermissionEntry();
spec_.clear();
}
diff --git a/chrome/common/extensions/permissions/socket_permission_data.h b/chrome/common/extensions/permissions/socket_permission_data.h
index 1a23cc2..d647568 100644
--- a/chrome/common/extensions/permissions/socket_permission_data.h
+++ b/chrome/common/extensions/permissions/socket_permission_data.h
@@ -6,9 +6,11 @@
#include <string>
-#include "base/memory/scoped_ptr.h"
#include "chrome/common/extensions/permissions/api_permission.h"
-#include "content/public/common/socket_permission_request.h"
+#include "chrome/common/extensions/permissions/socket_permission_entry.h"
+#include "ipc/ipc_param_traits.h"
+
+template <class T> struct FuzzTraits;
namespace extensions {
@@ -35,12 +37,6 @@
// The multicast membership permission implies a permission to any address.
class SocketPermissionData {
public:
- enum HostType {
- ANY_HOST,
- HOSTS_IN_DOMAINS,
- SPECIFIC_HOSTS,
- };
-
SocketPermissionData();
~SocketPermissionData();
@@ -59,33 +55,26 @@
// Populate |this| from a base::Value.
bool FromValue(const base::Value* value);
- // Returns true if the permission type can be bound to a host or port.
- bool IsAddressBoundType() const;
-
- HostType GetHostType() const;
- const std::string GetHost() const;
-
- const content::SocketPermissionRequest& pattern() const { return pattern_; }
- const bool& match_subdomains() const { return match_subdomains_; }
-
- // These accessors are provided for IPC_STRUCT_TRAITS_MEMBER. Please
- // think twice before using them for anything else.
- content::SocketPermissionRequest& pattern();
- bool& match_subdomains();
-
// TODO(bryeung): SocketPermissionData should be encoded as a base::Value
// instead of a string. Until that is done, expose these methods for
// testing.
bool ParseForTest(const std::string& permission) { return Parse(permission); }
const std::string& GetAsStringForTest() const { return GetAsString(); }
+ const SocketPermissionEntry& entry() const { return entry_; }
+
private:
+ // Friend so ParamTraits can serialize us.
+ friend struct IPC::ParamTraits<SocketPermissionData>;
+ friend struct FuzzTraits<SocketPermissionData>;
+
+ SocketPermissionEntry& entry();
+
bool Parse(const std::string& permission);
const std::string& GetAsString() const;
void Reset();
- content::SocketPermissionRequest pattern_;
- bool match_subdomains_;
+ SocketPermissionEntry entry_;
mutable std::string spec_;
};
diff --git a/chrome/common/extensions/permissions/socket_permission_entry.cc b/chrome/common/extensions/permissions/socket_permission_entry.cc
new file mode 100644
index 0000000..17f2ef7
--- /dev/null
+++ b/chrome/common/extensions/permissions/socket_permission_entry.cc
@@ -0,0 +1,227 @@
+// 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 "chrome/common/extensions/permissions/socket_permission_entry.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
+#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "url/url_canon.h"
+
+namespace {
+
+using content::SocketPermissionRequest;
+
+const char kColon = ':';
+const char kDot = '.';
+const char kWildcard[] = "*";
+const int kWildcardPortNumber = 0;
+const int kInvalidPort = -1;
+
+bool StartsOrEndsWithWhitespace(const std::string& str) {
+ if (str.find_first_not_of(kWhitespaceASCII) != 0)
+ return true;
+ if (str.find_last_not_of(kWhitespaceASCII) != str.length() - 1)
+ return true;
+ return false;
+}
+
+} // namespace
+
+namespace extensions {
+
+SocketPermissionEntry::SocketPermissionEntry()
+ : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort),
+ match_subdomains_(false) {
+}
+
+SocketPermissionEntry::~SocketPermissionEntry() {}
+
+bool SocketPermissionEntry::operator<(const SocketPermissionEntry& rhs) const {
+ if (pattern_.type < rhs.pattern_.type)
+ return true;
+ if (pattern_.type > rhs.pattern_.type)
+ return false;
+
+ if (pattern_.host < rhs.pattern_.host)
+ return true;
+ if (pattern_.host > rhs.pattern_.host)
+ return false;
+
+ if (match_subdomains_ < rhs.match_subdomains_)
+ return true;
+ if (match_subdomains_ > rhs.match_subdomains_)
+ return false;
+
+ if (pattern_.port < rhs.pattern_.port)
+ return true;
+ return false;
+}
+
+bool SocketPermissionEntry::operator==(const SocketPermissionEntry& rhs) const {
+ return (pattern_.type == rhs.pattern_.type) &&
+ (pattern_.host == rhs.pattern_.host) &&
+ (match_subdomains_ == rhs.match_subdomains_) &&
+ (pattern_.port == rhs.pattern_.port);
+}
+
+bool SocketPermissionEntry::Check(
+ const content::SocketPermissionRequest& request) const {
+ if (pattern_.type != request.type)
+ return false;
+
+ std::string lhost = StringToLowerASCII(request.host);
+ if (pattern_.host != lhost) {
+ if (!match_subdomains_)
+ return false;
+
+ if (!pattern_.host.empty()) {
+ // Do not wildcard part of IP address.
+ url_parse::Component component(0, lhost.length());
+ url_canon::RawCanonOutputT<char, 128> ignored_output;
+ url_canon::CanonHostInfo host_info;
+ url_canon::CanonicalizeIPAddress(lhost.c_str(), component,
+ &ignored_output, &host_info);
+ if (host_info.IsIPAddress())
+ return false;
+
+ // host should equal one or more chars + "." + host_.
+ int i = lhost.length() - pattern_.host.length();
+ if (i < 2)
+ return false;
+
+ if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
+ return false;
+
+ if (lhost[i - 1] != kDot)
+ return false;
+ }
+ }
+
+ if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
+ return false;
+
+ return true;
+}
+
+SocketPermissionEntry::HostType SocketPermissionEntry::GetHostType() const {
+ return pattern_.host.empty() ? SocketPermissionEntry::ANY_HOST :
+ match_subdomains_ ? SocketPermissionEntry::HOSTS_IN_DOMAINS :
+ SocketPermissionEntry::SPECIFIC_HOSTS;
+}
+
+bool SocketPermissionEntry::IsAddressBoundType() const {
+ return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
+ pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
+ pattern_.type == SocketPermissionRequest::UDP_BIND ||
+ pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
+}
+
+// static
+bool SocketPermissionEntry::ParseHostPattern(
+ SocketPermissionRequest::OperationType type,
+ const std::string& pattern,
+ SocketPermissionEntry* entry) {
+ std::vector<std::string> tokens;
+ base::SplitStringDontTrim(pattern, kColon, &tokens);
+ return ParseHostPattern(type, tokens, entry);
+}
+
+// static
+bool SocketPermissionEntry::ParseHostPattern(
+ SocketPermissionRequest::OperationType type,
+ const std::vector<std::string>& pattern_tokens,
+ SocketPermissionEntry* entry) {
+
+ SocketPermissionEntry result;
+
+ if (type == SocketPermissionRequest::NONE)
+ return false;
+
+ if (pattern_tokens.size() > 2)
+ return false;
+
+ result.pattern_.type = type;
+ result.pattern_.port = kWildcardPortNumber;
+ result.match_subdomains_ = true;
+
+ if (pattern_tokens.size() == 0) {
+ *entry = result;
+ return true;
+ }
+
+ // Return an error if address is specified for permissions that don't
+ // need it (such as 'resolve-host').
+ if (!result.IsAddressBoundType())
+ return false;
+
+ result.pattern_.host = pattern_tokens[0];
+ if (!result.pattern_.host.empty()) {
+ if (StartsOrEndsWithWhitespace(result.pattern_.host))
+ return false;
+ result.pattern_.host = StringToLowerASCII(result.pattern_.host);
+
+ // The first component can optionally be '*' to match all subdomains.
+ std::vector<std::string> host_components;
+ base::SplitString(result.pattern_.host, kDot, &host_components);
+ DCHECK(!host_components.empty());
+
+ if (host_components[0] == kWildcard || host_components[0].empty()) {
+ host_components.erase(host_components.begin(),
+ host_components.begin() + 1);
+ } else {
+ result.match_subdomains_ = false;
+ }
+ result.pattern_.host = JoinString(host_components, kDot);
+ }
+
+ if (pattern_tokens.size() == 1 ||
+ pattern_tokens[1].empty() ||
+ pattern_tokens[1] == kWildcard) {
+ *entry = result;
+ return true;
+ }
+
+ if (StartsOrEndsWithWhitespace(pattern_tokens[1]))
+ return false;
+
+ if (!base::StringToInt(pattern_tokens[1], &result.pattern_.port) ||
+ result.pattern_.port < 1 || result.pattern_.port > 65535)
+ return false;
+
+ *entry = result;
+ return true;
+}
+
+std::string SocketPermissionEntry::GetHostPatternAsString() const {
+ std::string result;
+
+ if (!IsAddressBoundType())
+ return result;
+
+ if (match_subdomains()) {
+ result.append(kWildcard);
+ if (!pattern_.host.empty())
+ result.append(1, kDot).append(pattern_.host);
+ } else {
+ result.append(pattern_.host);
+ }
+
+ if (pattern_.port == kWildcardPortNumber)
+ result.append(1, kColon).append(kWildcard);
+ else
+ result.append(1, kColon).append(base::IntToString(pattern_.port));
+
+ return result;
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/permissions/socket_permission_entry.h b/chrome/common/extensions/permissions/socket_permission_entry.h
new file mode 100644
index 0000000..b656471
--- /dev/null
+++ b/chrome/common/extensions/permissions/socket_permission_entry.h
@@ -0,0 +1,82 @@
+// 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 CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_
+#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_
+
+#include <string>
+#include <vector>
+
+#include "content/public/common/socket_permission_request.h"
+#include "ipc/ipc_param_traits.h"
+
+template <class T> struct FuzzTraits;
+
+namespace extensions {
+
+// Internal representation of a socket permission for a specific operation, such
+// as UDP "bind", host 127.0.0.1, port *.
+class SocketPermissionEntry {
+ public:
+ enum HostType {
+ ANY_HOST,
+ HOSTS_IN_DOMAINS,
+ SPECIFIC_HOSTS,
+ };
+
+ SocketPermissionEntry();
+ ~SocketPermissionEntry();
+
+ // operators <, == are needed by container std::set and algorithms
+ // std::set_includes and std::set_differences.
+ bool operator<(const SocketPermissionEntry& rhs) const;
+ bool operator==(const SocketPermissionEntry& rhs) const;
+
+ bool Check(const content::SocketPermissionRequest& request) const;
+
+ // Parse a host:port pattern for a given operation type.
+ // <pattern> := '' |
+ // <host> |
+ // ':' <port> |
+ // <host> ':' <port> |
+ //
+ // <host> := '*' |
+ // '*.' <anychar except '/' and '*'>+ |
+ // <anychar except '/' and '*'>+
+ //
+ // <port> := '*' |
+ // <port number between 0 and 65535>)
+ static bool ParseHostPattern(
+ content::SocketPermissionRequest::OperationType type,
+ const std::string& pattern,
+ SocketPermissionEntry* entry);
+
+ static bool ParseHostPattern(
+ content::SocketPermissionRequest::OperationType type,
+ const std::vector<std::string>& pattern_tokens,
+ SocketPermissionEntry* entry);
+
+ // Returns true if the permission type can be bound to a host or port.
+ bool IsAddressBoundType() const;
+
+ std::string GetHostPatternAsString() const;
+ HostType GetHostType() const;
+
+ const content::SocketPermissionRequest& pattern() const { return pattern_; }
+ bool match_subdomains() const { return match_subdomains_; }
+
+ private:
+ // Friend so ParamTraits can serialize us.
+ friend struct IPC::ParamTraits<SocketPermissionEntry>;
+ friend struct FuzzTraits<SocketPermissionEntry>;
+
+ // The permission type, host and port.
+ content::SocketPermissionRequest pattern_;
+
+ // True if there was a wildcard in the host name.
+ bool match_subdomains_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_