Index: chrome/common/extensions/permissions/socket_permission_data.cc |
diff --git a/chrome/common/extensions/permissions/socket_permission_data.cc b/chrome/common/extensions/permissions/socket_permission_data.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ef3c1918e5fe72c774db6750844008cf400e3766 |
--- /dev/null |
+++ b/chrome/common/extensions/permissions/socket_permission_data.cc |
@@ -0,0 +1,231 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/common/extensions/permissions/socket_permission_data.h" |
+ |
+#include <cstdlib> |
+#include <sstream> |
+#include <vector> |
+ |
+#include "base/logging.h" |
+#include "base/string_number_conversions.h" |
+#include "base/string_split.h" |
+#include "base/string_util.h" |
+#include "googleurl/src/url_canon.h" |
+ |
+namespace { |
+ |
+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"; |
+const char kUDPBind[] = "udp-bind"; |
+const char kUDPSendTo[] = "udp-send-to"; |
+const int kAnyPort = 0; |
+const int kInvalidPort = -1; |
+ |
+SocketPermissionData::OperationType StringToType(const std::string& s) { |
+ if (s == kTCPConnect) |
+ return SocketPermissionData::TCP_CONNECT; |
+ if (s == kTCPListen) |
+ return SocketPermissionData::TCP_LISTEN; |
+ if (s == kUDPBind) |
+ return SocketPermissionData::UDP_BIND; |
+ if (s == kUDPSendTo) |
+ return SocketPermissionData::UDP_SEND_TO; |
+ return SocketPermissionData::NONE; |
+} |
+ |
+const char* TypeToString(SocketPermissionData::OperationType type) { |
+ switch (type) { |
+ case SocketPermissionData::TCP_CONNECT: |
+ return kTCPConnect; |
+ case SocketPermissionData::TCP_LISTEN: |
+ return kTCPListen; |
+ case SocketPermissionData::UDP_BIND: |
+ return kUDPBind; |
+ case SocketPermissionData::UDP_SEND_TO: |
+ return kUDPSendTo; |
+ default: |
+ return kInvalid; |
+ } |
+} |
+ |
+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() { |
+ Reset(); |
+} |
+ |
+SocketPermissionData::~SocketPermissionData() { |
+} |
+ |
+bool SocketPermissionData::operator<(const SocketPermissionData& rhs) const { |
+ if (type_ < rhs.type_) |
+ return true; |
+ if (type_ > rhs.type_) |
+ return false; |
+ |
+ if (host_ < rhs.host_) |
+ return true; |
+ if (host_ > rhs.host_) |
+ return false; |
+ |
+ if (match_subdomains_ < rhs.match_subdomains_) |
+ return true; |
+ if (match_subdomains_ > rhs.match_subdomains_) |
+ return false; |
+ |
+ if (port_ < rhs.port_) |
+ return true; |
+ return false; |
+} |
+ |
+bool SocketPermissionData::operator==(const SocketPermissionData& rhs) const { |
+ return (type_ == rhs.type_) && (host_ == rhs.host_) && |
+ (match_subdomains_ == rhs.match_subdomains_) && |
+ (port_ == rhs.port_); |
+} |
+ |
+bool SocketPermissionData::Match( |
+ OperationType type, const std::string& host, int port) const { |
+ if (type_ != type) |
+ return false; |
+ |
+ std::string lhost = StringToLowerASCII(host); |
+ if (host_ != lhost) { |
+ if (!match_subdomains_) |
+ return false; |
+ |
+ if (!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() - host_.length(); |
+ if (i < 2) |
+ return false; |
+ |
+ if (lhost.compare(i, host_.length(), host_) != 0) |
+ return false; |
+ |
+ if (lhost[i - 1] != kDot) |
+ return false; |
+ } |
+ } |
+ |
+ if (port_ != port && port_ != kAnyPort) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+bool SocketPermissionData::Parse(const std::string& permission) { |
+ do { |
+ host_.clear(); |
+ match_subdomains_ = true; |
+ port_ = kAnyPort; |
+ spec_.clear(); |
+ |
+ std::vector<std::string> tokens; |
+ base::SplitStringDontTrim(permission, kColon, &tokens); |
+ |
+ if (tokens.empty() || tokens.size() > 3) |
+ break; |
+ |
+ type_ = StringToType(tokens[0]); |
+ if (type_ == NONE) |
+ break; |
+ |
+ if (tokens.size() == 1) |
+ return true; |
+ |
+ host_ = tokens[1]; |
+ if (!host_.empty()) { |
+ if (StartsOrEndsWithWhitespace(host_)) |
+ break; |
+ host_ = StringToLowerASCII(host_); |
+ |
+ // The first component can optionally be '*' to match all subdomains. |
+ std::vector<std::string> host_components; |
+ base::SplitString(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; |
+ } |
+ 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], &port_) || |
+ port_ < 1 || port_ > 65535) |
+ break; |
+ return true; |
+ } while (false); |
+ |
+ Reset(); |
+ return false; |
+} |
+ |
+const std::string& SocketPermissionData::GetAsString() const { |
+ if (!spec_.empty()) |
+ return spec_; |
+ |
+ spec_.reserve(64); |
+ spec_.append(TypeToString(type_)); |
+ |
+ if (match_subdomains_) { |
+ spec_.append(1, kColon).append(kWildcard); |
+ if (!host_.empty()) |
+ spec_.append(1, kDot).append(host_); |
+ } else { |
+ spec_.append(1, kColon).append(host_); |
+ } |
+ |
+ if (port_ == kAnyPort) |
+ spec_.append(1, kColon).append(kWildcard); |
+ else |
+ spec_.append(1, kColon).append(base::IntToString(port_)); |
+ |
+ return spec_; |
+} |
+ |
+void SocketPermissionData::Reset() { |
+ type_ = NONE; |
+ host_.clear(); |
+ match_subdomains_ = false; |
+ port_ = kInvalidPort; |
+ spec_.clear(); |
+} |
+ |
+} // namespace extensions |