Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / sockets_tcp / sockets_tcp_api.cc
blob0d20cd60f6f3bcc7b5c56ea7ea133d61b700c9fd
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/browser/api/sockets_tcp/sockets_tcp_api.h"
7 #include "content/public/browser/browser_context.h"
8 #include "content/public/common/socket_permission_request.h"
9 #include "extensions/browser/api/socket/tcp_socket.h"
10 #include "extensions/browser/api/socket/tls_socket.h"
11 #include "extensions/browser/api/sockets_tcp/tcp_socket_event_dispatcher.h"
12 #include "extensions/common/api/sockets/sockets_manifest_data.h"
13 #include "net/base/net_errors.h"
14 #include "net/url_request/url_request_context.h"
15 #include "net/url_request/url_request_context_getter.h"
17 using extensions::ResumableTCPSocket;
18 using extensions::api::sockets_tcp::SocketInfo;
19 using extensions::api::sockets_tcp::SocketProperties;
21 namespace {
23 const char kSocketNotFoundError[] = "Socket not found";
24 const char kPermissionError[] = "Does not have permission";
25 const char kInvalidSocketStateError[] =
26 "Socket must be a connected client TCP socket.";
27 const char kSocketNotConnectedError[] = "Socket not connected";
29 linked_ptr<SocketInfo> CreateSocketInfo(int socket_id,
30 ResumableTCPSocket* socket) {
31 linked_ptr<SocketInfo> socket_info(new SocketInfo());
32 // This represents what we know about the socket, and does not call through
33 // to the system.
34 socket_info->socket_id = socket_id;
35 if (!socket->name().empty()) {
36 socket_info->name.reset(new std::string(socket->name()));
38 socket_info->persistent = socket->persistent();
39 if (socket->buffer_size() > 0) {
40 socket_info->buffer_size.reset(new int(socket->buffer_size()));
42 socket_info->paused = socket->paused();
43 socket_info->connected = socket->IsConnected();
45 // Grab the local address as known by the OS.
46 net::IPEndPoint localAddress;
47 if (socket->GetLocalAddress(&localAddress)) {
48 socket_info->local_address.reset(
49 new std::string(localAddress.ToStringWithoutPort()));
50 socket_info->local_port.reset(new int(localAddress.port()));
53 // Grab the peer address as known by the OS. This and the call below will
54 // always succeed while the socket is connected, even if the socket has
55 // been remotely closed by the peer; only reading the socket will reveal
56 // that it should be closed locally.
57 net::IPEndPoint peerAddress;
58 if (socket->GetPeerAddress(&peerAddress)) {
59 socket_info->peer_address.reset(
60 new std::string(peerAddress.ToStringWithoutPort()));
61 socket_info->peer_port.reset(new int(peerAddress.port()));
64 return socket_info;
67 void SetSocketProperties(ResumableTCPSocket* socket,
68 SocketProperties* properties) {
69 if (properties->name.get()) {
70 socket->set_name(*properties->name.get());
72 if (properties->persistent.get()) {
73 socket->set_persistent(*properties->persistent.get());
75 if (properties->buffer_size.get()) {
76 // buffer size is validated when issuing the actual Recv operation
77 // on the socket.
78 socket->set_buffer_size(*properties->buffer_size.get());
82 } // namespace
84 namespace extensions {
85 namespace api {
87 using content::SocketPermissionRequest;
89 TCPSocketAsyncApiFunction::~TCPSocketAsyncApiFunction() {}
91 scoped_ptr<SocketResourceManagerInterface>
92 TCPSocketAsyncApiFunction::CreateSocketResourceManager() {
93 return scoped_ptr<SocketResourceManagerInterface>(
94 new SocketResourceManager<ResumableTCPSocket>()).Pass();
97 ResumableTCPSocket* TCPSocketAsyncApiFunction::GetTcpSocket(int socket_id) {
98 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
101 TCPSocketExtensionWithDnsLookupFunction::
102 ~TCPSocketExtensionWithDnsLookupFunction() {}
104 scoped_ptr<SocketResourceManagerInterface>
105 TCPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
106 return scoped_ptr<SocketResourceManagerInterface>(
107 new SocketResourceManager<ResumableTCPSocket>()).Pass();
110 ResumableTCPSocket* TCPSocketExtensionWithDnsLookupFunction::GetTcpSocket(
111 int socket_id) {
112 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
115 SocketsTcpCreateFunction::SocketsTcpCreateFunction() {}
117 SocketsTcpCreateFunction::~SocketsTcpCreateFunction() {}
119 bool SocketsTcpCreateFunction::Prepare() {
120 params_ = sockets_tcp::Create::Params::Create(*args_);
121 EXTENSION_FUNCTION_VALIDATE(params_.get());
122 return true;
125 void SocketsTcpCreateFunction::Work() {
126 ResumableTCPSocket* socket = new ResumableTCPSocket(extension_->id());
128 sockets_tcp::SocketProperties* properties = params_.get()->properties.get();
129 if (properties) {
130 SetSocketProperties(socket, properties);
133 sockets_tcp::CreateInfo create_info;
134 create_info.socket_id = AddSocket(socket);
135 results_ = sockets_tcp::Create::Results::Create(create_info);
138 SocketsTcpUpdateFunction::SocketsTcpUpdateFunction() {}
140 SocketsTcpUpdateFunction::~SocketsTcpUpdateFunction() {}
142 bool SocketsTcpUpdateFunction::Prepare() {
143 params_ = sockets_tcp::Update::Params::Create(*args_);
144 EXTENSION_FUNCTION_VALIDATE(params_.get());
145 return true;
148 void SocketsTcpUpdateFunction::Work() {
149 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
150 if (!socket) {
151 error_ = kSocketNotFoundError;
152 return;
155 SetSocketProperties(socket, &params_.get()->properties);
156 results_ = sockets_tcp::Update::Results::Create();
159 SocketsTcpSetPausedFunction::SocketsTcpSetPausedFunction()
160 : socket_event_dispatcher_(NULL) {}
162 SocketsTcpSetPausedFunction::~SocketsTcpSetPausedFunction() {}
164 bool SocketsTcpSetPausedFunction::Prepare() {
165 params_ = api::sockets_tcp::SetPaused::Params::Create(*args_);
166 EXTENSION_FUNCTION_VALIDATE(params_.get());
168 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
169 DCHECK(socket_event_dispatcher_)
170 << "There is no socket event dispatcher. "
171 "If this assertion is failing during a test, then it is likely that "
172 "TestExtensionSystem is failing to provide an instance of "
173 "TCPSocketEventDispatcher.";
174 return socket_event_dispatcher_ != NULL;
177 void SocketsTcpSetPausedFunction::Work() {
178 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
179 if (!socket) {
180 error_ = kSocketNotFoundError;
181 return;
184 if (socket->paused() != params_->paused) {
185 socket->set_paused(params_->paused);
186 if (socket->IsConnected() && !params_->paused) {
187 socket_event_dispatcher_->OnSocketResume(extension_->id(),
188 params_->socket_id);
192 results_ = sockets_tcp::SetPaused::Results::Create();
195 SocketsTcpSetKeepAliveFunction::SocketsTcpSetKeepAliveFunction() {}
197 SocketsTcpSetKeepAliveFunction::~SocketsTcpSetKeepAliveFunction() {}
199 bool SocketsTcpSetKeepAliveFunction::Prepare() {
200 params_ = api::sockets_tcp::SetKeepAlive::Params::Create(*args_);
201 EXTENSION_FUNCTION_VALIDATE(params_.get());
202 return true;
205 void SocketsTcpSetKeepAliveFunction::Work() {
206 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
207 if (!socket) {
208 error_ = kSocketNotFoundError;
209 return;
212 int delay = params_->delay ? *params_->delay.get() : 0;
214 bool success = socket->SetKeepAlive(params_->enable, delay);
215 int net_result = (success ? net::OK : net::ERR_FAILED);
216 if (net_result != net::OK)
217 error_ = net::ErrorToString(net_result);
218 results_ = sockets_tcp::SetKeepAlive::Results::Create(net_result);
221 SocketsTcpSetNoDelayFunction::SocketsTcpSetNoDelayFunction() {}
223 SocketsTcpSetNoDelayFunction::~SocketsTcpSetNoDelayFunction() {}
225 bool SocketsTcpSetNoDelayFunction::Prepare() {
226 params_ = api::sockets_tcp::SetNoDelay::Params::Create(*args_);
227 EXTENSION_FUNCTION_VALIDATE(params_.get());
228 return true;
231 void SocketsTcpSetNoDelayFunction::Work() {
232 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
233 if (!socket) {
234 error_ = kSocketNotFoundError;
235 return;
238 bool success = socket->SetNoDelay(params_->no_delay);
239 int net_result = (success ? net::OK : net::ERR_FAILED);
240 if (net_result != net::OK)
241 error_ = net::ErrorToString(net_result);
242 results_ = sockets_tcp::SetNoDelay::Results::Create(net_result);
245 SocketsTcpConnectFunction::SocketsTcpConnectFunction()
246 : socket_event_dispatcher_(NULL) {}
248 SocketsTcpConnectFunction::~SocketsTcpConnectFunction() {}
250 bool SocketsTcpConnectFunction::Prepare() {
251 params_ = sockets_tcp::Connect::Params::Create(*args_);
252 EXTENSION_FUNCTION_VALIDATE(params_.get());
254 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
255 DCHECK(socket_event_dispatcher_)
256 << "There is no socket event dispatcher. "
257 "If this assertion is failing during a test, then it is likely that "
258 "TestExtensionSystem is failing to provide an instance of "
259 "TCPSocketEventDispatcher.";
260 return socket_event_dispatcher_ != NULL;
263 void SocketsTcpConnectFunction::AsyncWorkStart() {
264 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
265 if (!socket) {
266 error_ = kSocketNotFoundError;
267 AsyncWorkCompleted();
268 return;
271 socket->set_hostname(params_->peer_address);
273 content::SocketPermissionRequest param(SocketPermissionRequest::TCP_CONNECT,
274 params_->peer_address,
275 params_->peer_port);
276 if (!SocketsManifestData::CheckRequest(extension(), param)) {
277 error_ = kPermissionError;
278 AsyncWorkCompleted();
279 return;
282 StartDnsLookup(net::HostPortPair(params_->peer_address, params_->peer_port));
285 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result) {
286 if (lookup_result == net::OK) {
287 StartConnect();
288 } else {
289 OnCompleted(lookup_result);
293 void SocketsTcpConnectFunction::StartConnect() {
294 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
295 if (!socket) {
296 error_ = kSocketNotFoundError;
297 AsyncWorkCompleted();
298 return;
301 socket->Connect(addresses_,
302 base::Bind(&SocketsTcpConnectFunction::OnCompleted, this));
305 void SocketsTcpConnectFunction::OnCompleted(int net_result) {
306 if (net_result == net::OK) {
307 socket_event_dispatcher_->OnSocketConnect(extension_->id(),
308 params_->socket_id);
311 if (net_result != net::OK)
312 error_ = net::ErrorToString(net_result);
313 results_ = sockets_tcp::Connect::Results::Create(net_result);
314 AsyncWorkCompleted();
317 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {}
319 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {}
321 bool SocketsTcpDisconnectFunction::Prepare() {
322 params_ = sockets_tcp::Disconnect::Params::Create(*args_);
323 EXTENSION_FUNCTION_VALIDATE(params_.get());
324 return true;
327 void SocketsTcpDisconnectFunction::Work() {
328 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
329 if (!socket) {
330 error_ = kSocketNotFoundError;
331 return;
334 socket->Disconnect();
335 results_ = sockets_tcp::Disconnect::Results::Create();
338 SocketsTcpSendFunction::SocketsTcpSendFunction() : io_buffer_size_(0) {}
340 SocketsTcpSendFunction::~SocketsTcpSendFunction() {}
342 bool SocketsTcpSendFunction::Prepare() {
343 params_ = sockets_tcp::Send::Params::Create(*args_);
344 EXTENSION_FUNCTION_VALIDATE(params_.get());
345 io_buffer_size_ = params_->data.size();
346 io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
347 return true;
350 void SocketsTcpSendFunction::AsyncWorkStart() {
351 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
352 if (!socket) {
353 error_ = kSocketNotFoundError;
354 AsyncWorkCompleted();
355 return;
358 socket->Write(io_buffer_,
359 io_buffer_size_,
360 base::Bind(&SocketsTcpSendFunction::OnCompleted, this));
363 void SocketsTcpSendFunction::OnCompleted(int net_result) {
364 if (net_result >= net::OK) {
365 SetSendResult(net::OK, net_result);
366 } else {
367 SetSendResult(net_result, -1);
371 void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) {
372 CHECK(net_result <= net::OK) << "Network status code must be <= net::OK";
374 sockets_tcp::SendInfo send_info;
375 send_info.result_code = net_result;
376 if (net_result == net::OK) {
377 send_info.bytes_sent.reset(new int(bytes_sent));
380 if (net_result != net::OK)
381 error_ = net::ErrorToString(net_result);
382 results_ = sockets_tcp::Send::Results::Create(send_info);
383 AsyncWorkCompleted();
386 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {}
388 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {}
390 bool SocketsTcpCloseFunction::Prepare() {
391 params_ = sockets_tcp::Close::Params::Create(*args_);
392 EXTENSION_FUNCTION_VALIDATE(params_.get());
393 return true;
396 void SocketsTcpCloseFunction::Work() {
397 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
398 if (!socket) {
399 error_ = kSocketNotFoundError;
400 return;
403 RemoveSocket(params_->socket_id);
404 results_ = sockets_tcp::Close::Results::Create();
407 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {}
409 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {}
411 bool SocketsTcpGetInfoFunction::Prepare() {
412 params_ = sockets_tcp::GetInfo::Params::Create(*args_);
413 EXTENSION_FUNCTION_VALIDATE(params_.get());
414 return true;
417 void SocketsTcpGetInfoFunction::Work() {
418 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
419 if (!socket) {
420 error_ = kSocketNotFoundError;
421 return;
424 linked_ptr<sockets_tcp::SocketInfo> socket_info =
425 CreateSocketInfo(params_->socket_id, socket);
426 results_ = sockets_tcp::GetInfo::Results::Create(*socket_info);
429 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {}
431 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {}
433 bool SocketsTcpGetSocketsFunction::Prepare() { return true; }
435 void SocketsTcpGetSocketsFunction::Work() {
436 std::vector<linked_ptr<sockets_tcp::SocketInfo> > socket_infos;
437 base::hash_set<int>* resource_ids = GetSocketIds();
438 if (resource_ids != NULL) {
439 for (base::hash_set<int>::iterator it = resource_ids->begin();
440 it != resource_ids->end();
441 ++it) {
442 int socket_id = *it;
443 ResumableTCPSocket* socket = GetTcpSocket(socket_id);
444 if (socket) {
445 socket_infos.push_back(CreateSocketInfo(socket_id, socket));
449 results_ = sockets_tcp::GetSockets::Results::Create(socket_infos);
452 SocketsTcpSecureFunction::SocketsTcpSecureFunction() {
455 SocketsTcpSecureFunction::~SocketsTcpSecureFunction() {
458 bool SocketsTcpSecureFunction::Prepare() {
459 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
460 params_ = api::sockets_tcp::Secure::Params::Create(*args_);
461 EXTENSION_FUNCTION_VALIDATE(params_.get());
462 url_request_getter_ = browser_context()->GetRequestContext();
463 return true;
466 // Override the regular implementation, which would call AsyncWorkCompleted
467 // immediately after Work().
468 void SocketsTcpSecureFunction::AsyncWorkStart() {
469 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
471 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
472 if (!socket) {
473 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
474 error_ = kSocketNotFoundError;
475 AsyncWorkCompleted();
476 return;
479 paused_ = socket->paused();
480 persistent_ = socket->persistent();
482 // Make sure it's a connected TCP client socket. Error out if it's already
483 // secure()'d.
484 if (socket->GetSocketType() != Socket::TYPE_TCP ||
485 socket->ClientStream() == NULL) {
486 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
487 error_ = kInvalidSocketStateError;
488 AsyncWorkCompleted();
489 return;
492 if (!socket->IsConnected()) {
493 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
494 error_ = kSocketNotConnectedError;
495 AsyncWorkCompleted();
496 return;
499 net::URLRequestContext* url_request_context =
500 url_request_getter_->GetURLRequestContext();
502 // UpgradeSocketToTLS() uses the older API's SecureOptions. Copy over the
503 // only values inside -- TLSVersionConstraints's |min| and |max|,
504 api::socket::SecureOptions legacy_params;
505 if (params_->options.get() && params_->options->tls_version.get()) {
506 legacy_params.tls_version.reset(new api::socket::TLSVersionConstraints);
507 if (params_->options->tls_version->min.get()) {
508 legacy_params.tls_version->min.reset(
509 new std::string(*params_->options->tls_version->min.get()));
511 if (params_->options->tls_version->max.get()) {
512 legacy_params.tls_version->max.reset(
513 new std::string(*params_->options->tls_version->max.get()));
517 TLSSocket::UpgradeSocketToTLS(
518 socket,
519 url_request_context->ssl_config_service(),
520 url_request_context->cert_verifier(),
521 url_request_context->transport_security_state(),
522 extension_id(),
523 &legacy_params,
524 base::Bind(&SocketsTcpSecureFunction::TlsConnectDone, this));
527 void SocketsTcpSecureFunction::TlsConnectDone(scoped_ptr<TLSSocket> socket,
528 int result) {
529 // If an error occurred, socket MUST be NULL
530 DCHECK(result == net::OK || socket == NULL);
532 if (socket && result == net::OK) {
533 socket->set_persistent(persistent_);
534 socket->set_paused(paused_);
535 ReplaceSocket(params_->socket_id, socket.release());
536 } else {
537 RemoveSocket(params_->socket_id);
538 error_ = net::ErrorToString(result);
541 results_ = api::sockets_tcp::Secure::Results::Create(result);
542 AsyncWorkCompleted();
545 } // namespace api
546 } // namespace extensions