1 // Copyright (c) 2012 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_data.h"
11 #include "base/logging.h"
12 #include "base/string_number_conversions.h"
13 #include "base/string_split.h"
14 #include "base/string_util.h"
15 #include "googleurl/src/url_canon.h"
19 using content::SocketPermissionRequest
;
20 using extensions::SocketPermissionData
;
22 const char kColon
= ':';
23 const char kDot
= '.';
24 const char kWildcard
[] = "*";
25 const char kInvalid
[] = "invalid";
26 const char kTCPConnect
[] = "tcp-connect";
27 const char kTCPListen
[] = "tcp-listen";
28 const char kUDPBind
[] = "udp-bind";
29 const char kUDPSendTo
[] = "udp-send-to";
30 const int kAnyPort
= 0;
31 const int kInvalidPort
= -1;
33 SocketPermissionRequest::OperationType
StringToType(const std::string
& s
) {
35 return SocketPermissionRequest::TCP_CONNECT
;
37 return SocketPermissionRequest::TCP_LISTEN
;
39 return SocketPermissionRequest::UDP_BIND
;
41 return SocketPermissionRequest::UDP_SEND_TO
;
42 return SocketPermissionRequest::NONE
;
45 const char* TypeToString(SocketPermissionRequest::OperationType type
) {
47 case SocketPermissionRequest::TCP_CONNECT
:
49 case SocketPermissionRequest::TCP_LISTEN
:
51 case SocketPermissionRequest::UDP_BIND
:
53 case SocketPermissionRequest::UDP_SEND_TO
:
60 bool StartsOrEndsWithWhitespace(const std::string
& str
) {
61 if (str
.find_first_not_of(kWhitespaceASCII
) != 0)
63 if (str
.find_last_not_of(kWhitespaceASCII
) != str
.length() - 1)
70 namespace extensions
{
72 SocketPermissionData::SocketPermissionData()
73 : pattern_(SocketPermissionRequest::NONE
, std::string(), kInvalidPort
) {
77 SocketPermissionData::~SocketPermissionData() {
80 bool SocketPermissionData::operator<(const SocketPermissionData
& rhs
) const {
81 if (pattern_
.type
< rhs
.pattern_
.type
)
83 if (pattern_
.type
> rhs
.pattern_
.type
)
86 if (pattern_
.host
< rhs
.pattern_
.host
)
88 if (pattern_
.host
> rhs
.pattern_
.host
)
91 if (match_subdomains_
< rhs
.match_subdomains_
)
93 if (match_subdomains_
> rhs
.match_subdomains_
)
96 if (pattern_
.port
< rhs
.pattern_
.port
)
101 bool SocketPermissionData::operator==(const SocketPermissionData
& rhs
) const {
102 return (pattern_
.type
== rhs
.pattern_
.type
) &&
103 (pattern_
.host
== rhs
.pattern_
.host
) &&
104 (match_subdomains_
== rhs
.match_subdomains_
) &&
105 (pattern_
.port
== rhs
.pattern_
.port
);
108 bool SocketPermissionData::Match(SocketPermissionRequest request
) const {
109 if (pattern_
.type
!= request
.type
)
112 std::string lhost
= StringToLowerASCII(request
.host
);
113 if (pattern_
.host
!= lhost
) {
114 if (!match_subdomains_
)
117 if (!pattern_
.host
.empty()) {
118 // Do not wildcard part of IP address.
119 url_parse::Component
component(0, lhost
.length());
120 url_canon::RawCanonOutputT
<char, 128> ignored_output
;
121 url_canon::CanonHostInfo host_info
;
122 url_canon::CanonicalizeIPAddress(lhost
.c_str(), component
,
123 &ignored_output
, &host_info
);
124 if (host_info
.IsIPAddress())
127 // host should equal one or more chars + "." + host_.
128 int i
= lhost
.length() - pattern_
.host
.length();
132 if (lhost
.compare(i
, pattern_
.host
.length(), pattern_
.host
) != 0)
135 if (lhost
[i
- 1] != kDot
)
140 if (pattern_
.port
!= request
.port
&& pattern_
.port
!= kAnyPort
)
146 bool SocketPermissionData::Parse(const std::string
& permission
) {
148 pattern_
.host
.clear();
149 match_subdomains_
= true;
150 pattern_
.port
= kAnyPort
;
153 std::vector
<std::string
> tokens
;
154 base::SplitStringDontTrim(permission
, kColon
, &tokens
);
156 if (tokens
.empty() || tokens
.size() > 3)
159 pattern_
.type
= StringToType(tokens
[0]);
160 if (pattern_
.type
== SocketPermissionRequest::NONE
)
163 if (tokens
.size() == 1)
166 pattern_
.host
= tokens
[1];
167 if (!pattern_
.host
.empty()) {
168 if (StartsOrEndsWithWhitespace(pattern_
.host
))
170 pattern_
.host
= StringToLowerASCII(pattern_
.host
);
172 // The first component can optionally be '*' to match all subdomains.
173 std::vector
<std::string
> host_components
;
174 base::SplitString(pattern_
.host
, kDot
, &host_components
);
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);
181 match_subdomains_
= false;
183 pattern_
.host
= JoinString(host_components
, kDot
);
186 if (tokens
.size() == 2 || tokens
[2].empty() || tokens
[2] == kWildcard
)
189 if (StartsOrEndsWithWhitespace(tokens
[2]))
192 if (!base::StringToInt(tokens
[2], &pattern_
.port
) ||
193 pattern_
.port
< 1 || pattern_
.port
> 65535)
202 SocketPermissionData::HostType
SocketPermissionData::GetHostType() const {
203 return pattern_
.host
.empty() ? SocketPermissionData::ANY_HOST
:
204 match_subdomains_
? SocketPermissionData::HOSTS_IN_DOMAINS
:
205 SocketPermissionData::SPECIFIC_HOSTS
;
208 const std::string
SocketPermissionData::GetHost() const {
209 return pattern_
.host
;
212 const std::string
& SocketPermissionData::GetAsString() const {
217 spec_
.append(TypeToString(pattern_
.type
));
219 if (match_subdomains_
) {
220 spec_
.append(1, kColon
).append(kWildcard
);
221 if (!pattern_
.host
.empty())
222 spec_
.append(1, kDot
).append(pattern_
.host
);
224 spec_
.append(1, kColon
).append(pattern_
.host
);
227 if (pattern_
.port
== kAnyPort
)
228 spec_
.append(1, kColon
).append(kWildcard
);
230 spec_
.append(1, kColon
).append(base::IntToString(pattern_
.port
));
235 void SocketPermissionData::Reset() {
236 pattern_
.type
= SocketPermissionRequest::NONE
;
237 pattern_
.host
.clear();
238 match_subdomains_
= false;
239 pattern_
.port
= kInvalidPort
;
243 } // namespace extensions