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"
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"
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]));
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
)
48 if (pattern_
.type
> rhs
.pattern_
.type
)
51 if (pattern_
.host
< rhs
.pattern_
.host
)
53 if (pattern_
.host
> rhs
.pattern_
.host
)
56 if (match_subdomains_
< rhs
.match_subdomains_
)
58 if (match_subdomains_
> rhs
.match_subdomains_
)
61 if (pattern_
.port
< rhs
.pattern_
.port
)
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
)
78 std::string lhost
= base::StringToLowerASCII(request
.host
);
79 if (pattern_
.host
!= lhost
) {
80 if (!match_subdomains_
)
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())
93 // host should equal one or more chars + "." + host_.
94 int i
= lhost
.length() - pattern_
.host
.length();
98 if (lhost
.compare(i
, pattern_
.host
.length(), pattern_
.host
) != 0)
101 if (lhost
[i
- 1] != kDot
)
106 if (pattern_
.port
!= request
.port
&& pattern_
.port
!= kWildcardPortNumber
)
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
;
127 bool SocketPermissionEntry::ParseHostPattern(
128 SocketPermissionRequest::OperationType type
,
129 const std::string
& pattern
,
130 SocketPermissionEntry
* entry
) {
131 std::vector
<std::string
> tokens
;
132 base::SplitStringDontTrim(pattern
, kColon
, &tokens
);
133 return ParseHostPattern(type
, tokens
, entry
);
137 bool SocketPermissionEntry::ParseHostPattern(
138 SocketPermissionRequest::OperationType type
,
139 const std::vector
<std::string
>& pattern_tokens
,
140 SocketPermissionEntry
* entry
) {
142 SocketPermissionEntry result
;
144 if (type
== SocketPermissionRequest::NONE
)
147 if (pattern_tokens
.size() > 2)
150 result
.pattern_
.type
= type
;
151 result
.pattern_
.port
= kWildcardPortNumber
;
152 result
.match_subdomains_
= true;
154 if (pattern_tokens
.size() == 0) {
159 // Return an error if address is specified for permissions that don't
160 // need it (such as 'resolve-host').
161 if (!result
.IsAddressBoundType())
164 result
.pattern_
.host
= pattern_tokens
[0];
165 if (!result
.pattern_
.host
.empty()) {
166 if (StartsOrEndsWithWhitespace(result
.pattern_
.host
))
168 result
.pattern_
.host
= base::StringToLowerASCII(result
.pattern_
.host
);
170 // The first component can optionally be '*' to match all subdomains.
171 std::vector
<std::string
> host_components
;
172 base::SplitString(result
.pattern_
.host
, kDot
, &host_components
);
173 DCHECK(!host_components
.empty());
175 if (host_components
[0] == kWildcard
|| host_components
[0].empty()) {
176 host_components
.erase(host_components
.begin(),
177 host_components
.begin() + 1);
179 result
.match_subdomains_
= false;
181 result
.pattern_
.host
= base::JoinString(host_components
, ".");
184 if (pattern_tokens
.size() == 1 || pattern_tokens
[1].empty() ||
185 pattern_tokens
[1] == kWildcard
) {
190 if (StartsOrEndsWithWhitespace(pattern_tokens
[1]))
194 if (!base::StringToInt(pattern_tokens
[1], &port
) || port
< 1 || port
> 65535)
196 result
.pattern_
.port
= static_cast<uint16
>(port
);
202 std::string
SocketPermissionEntry::GetHostPatternAsString() const {
205 if (!IsAddressBoundType())
208 if (match_subdomains()) {
209 result
.append(kWildcard
);
210 if (!pattern_
.host
.empty())
211 result
.append(1, kDot
).append(pattern_
.host
);
213 result
.append(pattern_
.host
);
216 if (pattern_
.port
== kWildcardPortNumber
)
217 result
.append(1, kColon
).append(kWildcard
);
219 result
.append(1, kColon
).append(base::IntToString(pattern_
.port
));
224 } // namespace extensions