1 // Copyright 2013 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 "chrome/common/extensions/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 "chrome/common/extensions/permissions/socket_permission.h"
17 #include "extensions/common/permissions/api_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 int kWildcardPortNumber
= 0;
28 const int kInvalidPort
= -1;
30 bool StartsOrEndsWithWhitespace(const std::string
& str
) {
31 if (str
.find_first_not_of(base::kWhitespaceASCII
) != 0)
33 if (str
.find_last_not_of(base::kWhitespaceASCII
) != str
.length() - 1)
40 namespace extensions
{
42 SocketPermissionEntry::SocketPermissionEntry()
43 : pattern_(SocketPermissionRequest::NONE
, std::string(), kInvalidPort
),
44 match_subdomains_(false) {
47 SocketPermissionEntry::~SocketPermissionEntry() {}
49 bool SocketPermissionEntry::operator<(const SocketPermissionEntry
& rhs
) const {
50 if (pattern_
.type
< rhs
.pattern_
.type
)
52 if (pattern_
.type
> rhs
.pattern_
.type
)
55 if (pattern_
.host
< rhs
.pattern_
.host
)
57 if (pattern_
.host
> rhs
.pattern_
.host
)
60 if (match_subdomains_
< rhs
.match_subdomains_
)
62 if (match_subdomains_
> rhs
.match_subdomains_
)
65 if (pattern_
.port
< rhs
.pattern_
.port
)
70 bool SocketPermissionEntry::operator==(const SocketPermissionEntry
& rhs
) const {
71 return (pattern_
.type
== rhs
.pattern_
.type
) &&
72 (pattern_
.host
== rhs
.pattern_
.host
) &&
73 (match_subdomains_
== rhs
.match_subdomains_
) &&
74 (pattern_
.port
== rhs
.pattern_
.port
);
77 bool SocketPermissionEntry::Check(
78 const content::SocketPermissionRequest
& request
) const {
79 if (pattern_
.type
!= request
.type
)
82 std::string lhost
= StringToLowerASCII(request
.host
);
83 if (pattern_
.host
!= lhost
) {
84 if (!match_subdomains_
)
87 if (!pattern_
.host
.empty()) {
88 // Do not wildcard part of IP address.
89 url_parse::Component
component(0, lhost
.length());
90 url_canon::RawCanonOutputT
<char, 128> ignored_output
;
91 url_canon::CanonHostInfo host_info
;
92 url_canon::CanonicalizeIPAddress(lhost
.c_str(), component
,
93 &ignored_output
, &host_info
);
94 if (host_info
.IsIPAddress())
97 // host should equal one or more chars + "." + host_.
98 int i
= lhost
.length() - pattern_
.host
.length();
102 if (lhost
.compare(i
, pattern_
.host
.length(), pattern_
.host
) != 0)
105 if (lhost
[i
- 1] != kDot
)
110 if (pattern_
.port
!= request
.port
&& pattern_
.port
!= kWildcardPortNumber
)
116 SocketPermissionEntry::HostType
SocketPermissionEntry::GetHostType() const {
117 return pattern_
.host
.empty() ? SocketPermissionEntry::ANY_HOST
:
118 match_subdomains_
? SocketPermissionEntry::HOSTS_IN_DOMAINS
:
119 SocketPermissionEntry::SPECIFIC_HOSTS
;
122 bool SocketPermissionEntry::IsAddressBoundType() const {
123 return pattern_
.type
== SocketPermissionRequest::TCP_CONNECT
||
124 pattern_
.type
== SocketPermissionRequest::TCP_LISTEN
||
125 pattern_
.type
== SocketPermissionRequest::UDP_BIND
||
126 pattern_
.type
== SocketPermissionRequest::UDP_SEND_TO
;
130 bool SocketPermissionEntry::ParseHostPattern(
131 SocketPermissionRequest::OperationType type
,
132 const std::string
& pattern
,
133 SocketPermissionEntry
* entry
) {
134 std::vector
<std::string
> tokens
;
135 base::SplitStringDontTrim(pattern
, kColon
, &tokens
);
136 return ParseHostPattern(type
, tokens
, entry
);
140 bool SocketPermissionEntry::ParseHostPattern(
141 SocketPermissionRequest::OperationType type
,
142 const std::vector
<std::string
>& pattern_tokens
,
143 SocketPermissionEntry
* entry
) {
145 SocketPermissionEntry result
;
147 if (type
== SocketPermissionRequest::NONE
)
150 if (pattern_tokens
.size() > 2)
153 result
.pattern_
.type
= type
;
154 result
.pattern_
.port
= kWildcardPortNumber
;
155 result
.match_subdomains_
= true;
157 if (pattern_tokens
.size() == 0) {
162 // Return an error if address is specified for permissions that don't
163 // need it (such as 'resolve-host').
164 if (!result
.IsAddressBoundType())
167 result
.pattern_
.host
= pattern_tokens
[0];
168 if (!result
.pattern_
.host
.empty()) {
169 if (StartsOrEndsWithWhitespace(result
.pattern_
.host
))
171 result
.pattern_
.host
= StringToLowerASCII(result
.pattern_
.host
);
173 // The first component can optionally be '*' to match all subdomains.
174 std::vector
<std::string
> host_components
;
175 base::SplitString(result
.pattern_
.host
, kDot
, &host_components
);
176 DCHECK(!host_components
.empty());
178 if (host_components
[0] == kWildcard
|| host_components
[0].empty()) {
179 host_components
.erase(host_components
.begin(),
180 host_components
.begin() + 1);
182 result
.match_subdomains_
= false;
184 result
.pattern_
.host
= JoinString(host_components
, kDot
);
187 if (pattern_tokens
.size() == 1 ||
188 pattern_tokens
[1].empty() ||
189 pattern_tokens
[1] == kWildcard
) {
194 if (StartsOrEndsWithWhitespace(pattern_tokens
[1]))
197 if (!base::StringToInt(pattern_tokens
[1], &result
.pattern_
.port
) ||
198 result
.pattern_
.port
< 1 || result
.pattern_
.port
> 65535)
205 std::string
SocketPermissionEntry::GetHostPatternAsString() const {
208 if (!IsAddressBoundType())
211 if (match_subdomains()) {
212 result
.append(kWildcard
);
213 if (!pattern_
.host
.empty())
214 result
.append(1, kDot
).append(pattern_
.host
);
216 result
.append(pattern_
.host
);
219 if (pattern_
.port
== kWildcardPortNumber
)
220 result
.append(1, kColon
).append(kWildcard
);
222 result
.append(1, kColon
).append(base::IntToString(pattern_
.port
));
227 } // namespace extensions