Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / common / permissions / socket_permission_entry.cc
blob012eda001b4c03df14d440158b68095019ca9d18
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/common/permissions/socket_permission_entry.h"
7 #include <cstdlib>
8 #include <sstream>
9 #include <vector>
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "extensions/common/permissions/api_permission.h"
17 #include "extensions/common/permissions/socket_permission.h"
18 #include "url/url_canon.h"
20 namespace {
22 using content::SocketPermissionRequest;
24 const char kColon = ':';
25 const char kDot = '.';
26 const char kWildcard[] = "*";
27 const uint16 kWildcardPortNumber = 0;
28 const uint16 kInvalidPort = 65535;
30 bool StartsOrEndsWithWhitespace(const std::string& str) {
31 return !str.empty() && (base::IsUnicodeWhitespace(str[0]) ||
32 base::IsUnicodeWhitespace(str[str.length() - 1]));
35 } // namespace
37 namespace extensions {
39 SocketPermissionEntry::SocketPermissionEntry()
40 : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort),
41 match_subdomains_(false) {}
43 SocketPermissionEntry::~SocketPermissionEntry() {}
45 bool SocketPermissionEntry::operator<(const SocketPermissionEntry& rhs) const {
46 if (pattern_.type < rhs.pattern_.type)
47 return true;
48 if (pattern_.type > rhs.pattern_.type)
49 return false;
51 if (pattern_.host < rhs.pattern_.host)
52 return true;
53 if (pattern_.host > rhs.pattern_.host)
54 return false;
56 if (match_subdomains_ < rhs.match_subdomains_)
57 return true;
58 if (match_subdomains_ > rhs.match_subdomains_)
59 return false;
61 if (pattern_.port < rhs.pattern_.port)
62 return true;
63 return false;
66 bool SocketPermissionEntry::operator==(const SocketPermissionEntry& rhs) const {
67 return (pattern_.type == rhs.pattern_.type) &&
68 (pattern_.host == rhs.pattern_.host) &&
69 (match_subdomains_ == rhs.match_subdomains_) &&
70 (pattern_.port == rhs.pattern_.port);
73 bool SocketPermissionEntry::Check(
74 const content::SocketPermissionRequest& request) const {
75 if (pattern_.type != request.type)
76 return false;
78 std::string lhost = base::ToLowerASCII(request.host);
79 if (pattern_.host != lhost) {
80 if (!match_subdomains_)
81 return false;
83 if (!pattern_.host.empty()) {
84 // Do not wildcard part of IP address.
85 url::Component component(0, lhost.length());
86 url::RawCanonOutputT<char, 128> ignored_output;
87 url::CanonHostInfo host_info;
88 url::CanonicalizeIPAddress(
89 lhost.c_str(), component, &ignored_output, &host_info);
90 if (host_info.IsIPAddress())
91 return false;
93 // host should equal one or more chars + "." + host_.
94 int i = lhost.length() - pattern_.host.length();
95 if (i < 2)
96 return false;
98 if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
99 return false;
101 if (lhost[i - 1] != kDot)
102 return false;
106 if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
107 return false;
109 return true;
112 SocketPermissionEntry::HostType SocketPermissionEntry::GetHostType() const {
113 return pattern_.host.empty()
114 ? SocketPermissionEntry::ANY_HOST
115 : match_subdomains_ ? SocketPermissionEntry::HOSTS_IN_DOMAINS
116 : SocketPermissionEntry::SPECIFIC_HOSTS;
119 bool SocketPermissionEntry::IsAddressBoundType() const {
120 return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
121 pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
122 pattern_.type == SocketPermissionRequest::UDP_BIND ||
123 pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
126 // static
127 bool SocketPermissionEntry::ParseHostPattern(
128 SocketPermissionRequest::OperationType type,
129 const std::string& pattern,
130 SocketPermissionEntry* entry) {
131 std::vector<std::string> tokens =
132 base::SplitString(pattern, std::string(1, kColon), base::KEEP_WHITESPACE,
133 base::SPLIT_WANT_ALL);
134 return ParseHostPattern(type, tokens, entry);
137 // static
138 bool SocketPermissionEntry::ParseHostPattern(
139 SocketPermissionRequest::OperationType type,
140 const std::vector<std::string>& pattern_tokens,
141 SocketPermissionEntry* entry) {
143 SocketPermissionEntry result;
145 if (type == SocketPermissionRequest::NONE)
146 return false;
148 if (pattern_tokens.size() > 2)
149 return false;
151 result.pattern_.type = type;
152 result.pattern_.port = kWildcardPortNumber;
153 result.match_subdomains_ = true;
155 if (pattern_tokens.size() == 0) {
156 *entry = result;
157 return true;
160 // Return an error if address is specified for permissions that don't
161 // need it (such as 'resolve-host').
162 if (!result.IsAddressBoundType())
163 return false;
165 result.pattern_.host = pattern_tokens[0];
166 if (!result.pattern_.host.empty()) {
167 if (StartsOrEndsWithWhitespace(result.pattern_.host))
168 return false;
169 result.pattern_.host = base::ToLowerASCII(result.pattern_.host);
171 // The first component can optionally be '*' to match all subdomains.
172 std::vector<std::string> host_components =
173 base::SplitString(result.pattern_.host, std::string(1, kDot),
174 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
175 DCHECK(!host_components.empty());
177 if (host_components[0] == kWildcard || host_components[0].empty()) {
178 host_components.erase(host_components.begin(),
179 host_components.begin() + 1);
180 } else {
181 result.match_subdomains_ = false;
183 result.pattern_.host = base::JoinString(host_components, ".");
186 if (pattern_tokens.size() == 1 || pattern_tokens[1].empty() ||
187 pattern_tokens[1] == kWildcard) {
188 *entry = result;
189 return true;
192 if (StartsOrEndsWithWhitespace(pattern_tokens[1]))
193 return false;
195 int port;
196 if (!base::StringToInt(pattern_tokens[1], &port) || port < 1 || port > 65535)
197 return false;
198 result.pattern_.port = static_cast<uint16>(port);
200 *entry = result;
201 return true;
204 std::string SocketPermissionEntry::GetHostPatternAsString() const {
205 std::string result;
207 if (!IsAddressBoundType())
208 return result;
210 if (match_subdomains()) {
211 result.append(kWildcard);
212 if (!pattern_.host.empty())
213 result.append(1, kDot).append(pattern_.host);
214 } else {
215 result.append(pattern_.host);
218 if (pattern_.port == kWildcardPortNumber)
219 result.append(1, kColon).append(kWildcard);
220 else
221 result.append(1, kColon).append(base::IntToString(pattern_.port));
223 return result;
226 } // namespace extensions