Extract SIGPIPE ignoring code to a common place.
[chromium-blink-merge.git] / chrome / common / extensions / permissions / socket_permission_data.cc
blobbd9f041d02706268a90c6857b325e1427f9309c3
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"
7 #include <cstdlib>
8 #include <sstream>
9 #include <vector>
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"
17 namespace {
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) {
34 if (s == kTCPConnect)
35 return SocketPermissionRequest::TCP_CONNECT;
36 if (s == kTCPListen)
37 return SocketPermissionRequest::TCP_LISTEN;
38 if (s == kUDPBind)
39 return SocketPermissionRequest::UDP_BIND;
40 if (s == kUDPSendTo)
41 return SocketPermissionRequest::UDP_SEND_TO;
42 return SocketPermissionRequest::NONE;
45 const char* TypeToString(SocketPermissionRequest::OperationType type) {
46 switch (type) {
47 case SocketPermissionRequest::TCP_CONNECT:
48 return kTCPConnect;
49 case SocketPermissionRequest::TCP_LISTEN:
50 return kTCPListen;
51 case SocketPermissionRequest::UDP_BIND:
52 return kUDPBind;
53 case SocketPermissionRequest::UDP_SEND_TO:
54 return kUDPSendTo;
55 default:
56 return kInvalid;
60 bool StartsOrEndsWithWhitespace(const std::string& str) {
61 if (str.find_first_not_of(kWhitespaceASCII) != 0)
62 return true;
63 if (str.find_last_not_of(kWhitespaceASCII) != str.length() - 1)
64 return true;
65 return false;
68 } // namespace
70 namespace extensions {
72 SocketPermissionData::SocketPermissionData()
73 : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort) {
74 Reset();
77 SocketPermissionData::~SocketPermissionData() {
80 bool SocketPermissionData::operator<(const SocketPermissionData& rhs) const {
81 if (pattern_.type < rhs.pattern_.type)
82 return true;
83 if (pattern_.type > rhs.pattern_.type)
84 return false;
86 if (pattern_.host < rhs.pattern_.host)
87 return true;
88 if (pattern_.host > rhs.pattern_.host)
89 return false;
91 if (match_subdomains_ < rhs.match_subdomains_)
92 return true;
93 if (match_subdomains_ > rhs.match_subdomains_)
94 return false;
96 if (pattern_.port < rhs.pattern_.port)
97 return true;
98 return false;
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)
110 return false;
112 std::string lhost = StringToLowerASCII(request.host);
113 if (pattern_.host != lhost) {
114 if (!match_subdomains_)
115 return false;
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())
125 return false;
127 // host should equal one or more chars + "." + host_.
128 int i = lhost.length() - pattern_.host.length();
129 if (i < 2)
130 return false;
132 if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
133 return false;
135 if (lhost[i - 1] != kDot)
136 return false;
140 if (pattern_.port != request.port && pattern_.port != kAnyPort)
141 return false;
143 return true;
146 bool SocketPermissionData::Parse(const std::string& permission) {
147 do {
148 pattern_.host.clear();
149 match_subdomains_ = true;
150 pattern_.port = kAnyPort;
151 spec_.clear();
153 std::vector<std::string> tokens;
154 base::SplitStringDontTrim(permission, kColon, &tokens);
156 if (tokens.empty() || tokens.size() > 3)
157 break;
159 pattern_.type = StringToType(tokens[0]);
160 if (pattern_.type == SocketPermissionRequest::NONE)
161 break;
163 if (tokens.size() == 1)
164 return true;
166 pattern_.host = tokens[1];
167 if (!pattern_.host.empty()) {
168 if (StartsOrEndsWithWhitespace(pattern_.host))
169 break;
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);
180 } else {
181 match_subdomains_ = false;
183 pattern_.host = JoinString(host_components, kDot);
186 if (tokens.size() == 2 || tokens[2].empty() || tokens[2] == kWildcard)
187 return true;
189 if (StartsOrEndsWithWhitespace(tokens[2]))
190 break;
192 if (!base::StringToInt(tokens[2], &pattern_.port) ||
193 pattern_.port < 1 || pattern_.port > 65535)
194 break;
195 return true;
196 } while (false);
198 Reset();
199 return false;
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 {
213 if (!spec_.empty())
214 return spec_;
216 spec_.reserve(64);
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);
223 } else {
224 spec_.append(1, kColon).append(pattern_.host);
227 if (pattern_.port == kAnyPort)
228 spec_.append(1, kColon).append(kWildcard);
229 else
230 spec_.append(1, kColon).append(base::IntToString(pattern_.port));
232 return spec_;
235 void SocketPermissionData::Reset() {
236 pattern_.type = SocketPermissionRequest::NONE;
237 pattern_.host.clear();
238 match_subdomains_ = false;
239 pattern_.port = kInvalidPort;
240 spec_.clear();
243 } // namespace extensions