Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: chrome/browser/extensions/api/socket/socket_api.cc

Issue 76403004: An implementation of chrome.socket.secure(). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixing another cross-platform build issue (try 2) Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/socket/socket_api.h" 5 #include "chrome/browser/extensions/api/socket/socket_api.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/containers/hash_tables.h" 10 #include "base/containers/hash_tables.h"
11 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/api/dns/host_resolver_wrapper.h" 12 #include "chrome/browser/extensions/api/dns/host_resolver_wrapper.h"
13 #include "chrome/browser/extensions/api/socket/socket.h" 13 #include "chrome/browser/extensions/api/socket/socket.h"
14 #include "chrome/browser/extensions/api/socket/tcp_socket.h" 14 #include "chrome/browser/extensions/api/socket/tcp_socket.h"
15 #include "chrome/browser/extensions/api/socket/tls_socket.h"
15 #include "chrome/browser/extensions/api/socket/udp_socket.h" 16 #include "chrome/browser/extensions/api/socket/udp_socket.h"
16 #include "chrome/browser/extensions/extension_system.h" 17 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/io_thread.h" 18 #include "chrome/browser/io_thread.h"
18 #include "chrome/common/extensions/permissions/socket_permission.h" 19 #include "chrome/common/extensions/permissions/socket_permission.h"
19 #include "extensions/common/extension.h" 20 #include "extensions/common/extension.h"
20 #include "extensions/common/permissions/permissions_data.h" 21 #include "extensions/common/permissions/permissions_data.h"
21 #include "net/base/host_port_pair.h" 22 #include "net/base/host_port_pair.h"
22 #include "net/base/io_buffer.h" 23 #include "net/base/io_buffer.h"
23 #include "net/base/ip_endpoint.h" 24 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h" 25 #include "net/base/net_errors.h"
25 #include "net/base/net_log.h" 26 #include "net/base/net_log.h"
26 #include "net/base/net_util.h" 27 #include "net/base/net_util.h"
28 #include "net/socket/client_socket_handle.h"
29 #include "net/socket/client_socket_factory.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_context_getter.h"
27 32
28 namespace extensions { 33 namespace extensions {
29 34
30 using content::SocketPermissionRequest; 35 using content::SocketPermissionRequest;
31 36
32 const char kAddressKey[] = "address"; 37 const char kAddressKey[] = "address";
33 const char kPortKey[] = "port"; 38 const char kPortKey[] = "port";
34 const char kBytesWrittenKey[] = "bytesWritten"; 39 const char kBytesWrittenKey[] = "bytesWritten";
35 const char kDataKey[] = "data"; 40 const char kDataKey[] = "data";
36 const char kResultCodeKey[] = "resultCode"; 41 const char kResultCodeKey[] = "resultCode";
37 const char kSocketIdKey[] = "socketId"; 42 const char kSocketIdKey[] = "socketId";
38 43
39 const char kSocketNotFoundError[] = "Socket not found"; 44 const char kSocketNotFoundError[] = "Socket not found";
40 const char kDnsLookupFailedError[] = "DNS resolution failed"; 45 const char kDnsLookupFailedError[] = "DNS resolution failed";
41 const char kPermissionError[] = "App does not have permission"; 46 const char kPermissionError[] = "App does not have permission";
42 const char kNetworkListError[] = "Network lookup failed or unsupported"; 47 const char kNetworkListError[] = "Network lookup failed or unsupported";
43 const char kTCPSocketBindError[] = 48 const char kTCPSocketBindError[] =
44 "TCP socket does not support bind. For TCP server please use listen."; 49 "TCP socket does not support bind. For TCP server please use listen.";
45 const char kMulticastSocketTypeError[] = 50 const char kMulticastSocketTypeError[] =
46 "Only UDP socket supports multicast."; 51 "Only UDP socket supports multicast.";
52 const char kSecureSocketTypeError[] =
53 "Only TCP sockets are supported for TLS.";
54 const char kSocketNotConnectedError[] = "Socket not connected";
47 const char kWildcardAddress[] = "*"; 55 const char kWildcardAddress[] = "*";
48 const int kWildcardPort = 0; 56 const int kWildcardPort = 0;
49 57
58 namespace {
59 // Returns the SSL protocol version (as a uint16) represented by a string.
60 // Returns 0 if the string is invalid. Pulled from
61 // chrome/browser/net/ssl_config_service_manager_pref.cc.
62 uint16 SSLProtocolVersionFromString(const std::string& version_str) {
63 uint16 version = 0; // Invalid.
64 if (version_str == "ssl3") {
65 version = net::SSL_PROTOCOL_VERSION_SSL3;
66 } else if (version_str == "tls1") {
67 version = net::SSL_PROTOCOL_VERSION_TLS1;
68 } else if (version_str == "tls1.1") {
69 version = net::SSL_PROTOCOL_VERSION_TLS1_1;
70 } else if (version_str == "tls1.2") {
71 version = net::SSL_PROTOCOL_VERSION_TLS1_2;
72 }
73 return version;
74 }
75 } // namespace
76
77
50 SocketAsyncApiFunction::SocketAsyncApiFunction() { 78 SocketAsyncApiFunction::SocketAsyncApiFunction() {
51 } 79 }
52 80
53 SocketAsyncApiFunction::~SocketAsyncApiFunction() { 81 SocketAsyncApiFunction::~SocketAsyncApiFunction() {
54 } 82 }
55 83
56 bool SocketAsyncApiFunction::PrePrepare() { 84 bool SocketAsyncApiFunction::PrePrepare() {
57 manager_ = CreateSocketResourceManager(); 85 manager_ = CreateSocketResourceManager();
58 return manager_->SetProfile(GetProfile()); 86 return manager_->SetProfile(GetProfile());
59 } 87 }
60 88
61 bool SocketAsyncApiFunction::Respond() { 89 bool SocketAsyncApiFunction::Respond() {
62 return error_.empty(); 90 return error_.empty();
63 } 91 }
64 92
65 scoped_ptr<SocketResourceManagerInterface> 93 scoped_ptr<SocketResourceManagerInterface>
66 SocketAsyncApiFunction::CreateSocketResourceManager() { 94 SocketAsyncApiFunction::CreateSocketResourceManager() {
67 return scoped_ptr<SocketResourceManagerInterface>( 95 return scoped_ptr<SocketResourceManagerInterface>(
68 new SocketResourceManager<Socket>()).Pass(); 96 new SocketResourceManager<Socket>()).Pass();
69 } 97 }
70 98
71 int SocketAsyncApiFunction::AddSocket(Socket* socket) { 99 int SocketAsyncApiFunction::AddSocket(Socket* socket) {
72 return manager_->Add(socket); 100 return manager_->Add(socket);
73 } 101 }
74 102
75 Socket* SocketAsyncApiFunction::GetSocket(int api_resource_id) { 103 Socket* SocketAsyncApiFunction::GetSocket(int api_resource_id) {
76 return manager_->Get(extension_->id(), api_resource_id); 104 return manager_->Get(extension_->id(), api_resource_id);
77 } 105 }
78 106
107 void SocketAsyncApiFunction::SetSocket(int api_resource_id,
108 Socket* socket) {
109 manager_->Set(extension_->id(), api_resource_id, socket);
110 }
111
79 base::hash_set<int>* SocketAsyncApiFunction::GetSocketIds() { 112 base::hash_set<int>* SocketAsyncApiFunction::GetSocketIds() {
80 return manager_->GetResourceIds(extension_->id()); 113 return manager_->GetResourceIds(extension_->id());
81 } 114 }
82 115
83 void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) { 116 void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) {
84 manager_->Remove(extension_->id(), api_resource_id); 117 manager_->Remove(extension_->id(), api_resource_id);
85 } 118 }
86 119
87 SocketExtensionWithDnsLookupFunction::SocketExtensionWithDnsLookupFunction() 120 SocketExtensionWithDnsLookupFunction::SocketExtensionWithDnsLookupFunction()
88 : io_thread_(g_browser_process->io_thread()), 121 : io_thread_(g_browser_process->io_thread()),
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 void SocketConnectFunction::AfterDnsLookup(int lookup_result) { 265 void SocketConnectFunction::AfterDnsLookup(int lookup_result) {
233 if (lookup_result == net::OK) { 266 if (lookup_result == net::OK) {
234 StartConnect(); 267 StartConnect();
235 } else { 268 } else {
236 SetResult(new base::FundamentalValue(lookup_result)); 269 SetResult(new base::FundamentalValue(lookup_result));
237 AsyncWorkCompleted(); 270 AsyncWorkCompleted();
238 } 271 }
239 } 272 }
240 273
241 void SocketConnectFunction::StartConnect() { 274 void SocketConnectFunction::StartConnect() {
275 socket_->SetOriginalHostname(hostname_);
242 socket_->Connect(resolved_address_, port_, 276 socket_->Connect(resolved_address_, port_,
243 base::Bind(&SocketConnectFunction::OnConnect, this)); 277 base::Bind(&SocketConnectFunction::OnConnect, this));
244 } 278 }
245 279
246 void SocketConnectFunction::OnConnect(int result) { 280 void SocketConnectFunction::OnConnect(int result) {
247 SetResult(new base::FundamentalValue(result)); 281 SetResult(new base::FundamentalValue(result));
248 AsyncWorkCompleted(); 282 AsyncWorkCompleted();
249 } 283 }
250 284
251 bool SocketDisconnectFunction::Prepare() { 285 bool SocketDisconnectFunction::Prepare() {
(...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 SetResult(new base::FundamentalValue(result)); 923 SetResult(new base::FundamentalValue(result));
890 return; 924 return;
891 } 925 }
892 926
893 base::ListValue* values = new base::ListValue(); 927 base::ListValue* values = new base::ListValue();
894 values->AppendStrings((std::vector<std::string>&) 928 values->AppendStrings((std::vector<std::string>&)
895 static_cast<UDPSocket*>(socket)->GetJoinedGroups()); 929 static_cast<UDPSocket*>(socket)->GetJoinedGroups());
896 SetResult(values); 930 SetResult(values);
897 } 931 }
898 932
933 SocketSecureFunction::SocketSecureFunction() {}
934 SocketSecureFunction::~SocketSecureFunction() {}
935
936 bool SocketSecureFunction::Prepare() {
937 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
938 VLOG(1) << "chrome.socket.secure: Prepare()";
939 params_ = api::socket::Secure::Params::Create(*args_);
940 EXTENSION_FUNCTION_VALIDATE(params_.get());
941 url_request_getter_ = GetProfile()->GetRequestContext();
942 underlying_socket_ = NULL;
943 return true;
944 }
945
946 void SocketSecureFunction::Work() {
947 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
948 VLOG(1) << "chrome.socket.secure: Work()";
949 Socket* socket = GetSocket(params_->socket_id);
950 int result = -1;
951 if (!socket) {
952 error_ = kSocketNotFoundError;
953 SetResult(new base::FundamentalValue(result));
954 VLOG(1) << "chrome.socket.secure: Work(): no socket, bolting.";
Ryan Sleevi 2013/11/25 17:30:13 These VLOGs are all included in release/official b
Lally Singh 2013/12/05 17:07:12 All but 1 removed. The remainder moved to DVLOG (
955 return;
956 }
957
958 if (socket->GetSocketType() != Socket::TYPE_TCP) {
959 error_ = kSecureSocketTypeError;
960 SetResult(new base::FundamentalValue(result));
961 VLOG(1) << "chrome.socket.secure: Work(): not a TCP socket, bolting.";
962 return;
963 }
964
965 if (!socket->IsConnected()) {
966 error_ = kSocketNotConnectedError;
967 SetResult(new base::FundamentalValue(result));
968 VLOG(1) << "chrome.socket.secure: Work(): unconnected socket, bolting.";
969 return;
970 }
971
972 VLOG(1) << "SocketSecureFunction::Work: Starting up";
973
974 net::IPEndPoint dest_host_port_pair;
975 socket->GetPeerAddress(&dest_host_port_pair);
976 net::HostPortPair host_port(
977 socket->OriginalHostname(),
978 dest_host_port_pair.port());
979
980 // Modeled after content/browser/renderer_host/p2p/socket_host_tcp.cc:154
981 // P2PSocketHostTcpBase::StartTls()
Ryan Sleevi 2013/11/25 17:30:13 Don't do comments like this. It will be out of dat
Lally Singh 2013/12/05 17:07:12 Acknowledged. The file/line# were removed, but th
982 scoped_ptr<net::ClientSocketHandle> socket_handle(
983 new net::ClientSocketHandle());
984 // We already know from GetSocketType() above that it's TCP.
Ryan Sleevi 2013/11/25 17:30:13 nit: Please rework the comments here to avoid the
Lally Singh 2013/12/05 17:07:12 This comment was removed, but instances of "we" we
985 TCPSocket *tcp_socket = static_cast<TCPSocket*>(socket);
986 DCHECK(tcp_socket->ClientStream());
987
988 // We keep a pointer (not a lifetime-preserving reference) to the original
989 // TCPClientSocket, to give to TLSSocket upon successful TLS negotiation.
990 // Its properly owned by ssl_socket_, which doesn't pass through certain
991 // APIs that we'd like it to (SetKeepAlive, SetNoDelay).
Ryan Sleevi 2013/11/25 17:30:13 This is a bug. You shouldn't be doing this. Set yo
Lally Singh 2013/12/05 17:07:12 I've disabled the KeepAlive/NoDelay methods. The
992 underlying_socket_ = tcp_socket->ClientStream();
993 socket_handle->SetSocket(scoped_ptr<net::StreamSocket>(underlying_socket_));
994
995 // Have the old socket release its holds on the client stream we just gave
996 // away.
997 tcp_socket->Release();
998
999 net::SSLClientSocketContext context;
1000 Profile* profile = GetProfile();
1001 DCHECK(profile);
1002 net::URLRequestContext* url_context =
1003 url_request_getter_->GetURLRequestContext();
1004
1005 DCHECK(url_context);
1006 context.cert_verifier = url_context->cert_verifier();
1007 context.transport_security_state = url_context->transport_security_state();
1008 DCHECK(context.transport_security_state);
1009
1010 // Fill in the SSL socket params.
1011 net::SSLConfig ssl_config;
1012 profile->GetSSLConfigService()->GetSSLConfig(&ssl_config);
1013 if (params_->options.get() && params_->options->tls_version.get()) {
1014 uint16 v_min = 0, v_max = 0;
Ryan Sleevi 2013/11/25 17:30:13 As per the Google C++ style guide, eschew abbrevia
Lally Singh 2013/12/05 17:07:12 Done.
1015 api::socket::TLSVersionConstraints *versions =
Ryan Sleevi 2013/11/25 17:30:13 As per http://www.chromium.org/developers/coding-s
Lally Singh 2013/12/05 17:07:12 Done.
1016 params_->options->tls_version.get();
1017 if (versions->min.get()) {
1018 v_min = SSLProtocolVersionFromString(*versions->min.get());
1019 }
1020 if (versions->max.get()) {
1021 v_max = SSLProtocolVersionFromString(*versions->max.get());
1022 }
1023 if (v_min) {
1024 ssl_config.version_min = v_min;
1025 }
1026 if (v_max) {
1027 ssl_config.version_max = v_max;
1028 }
1029 }
1030 net::ClientSocketFactory* socket_factory =
1031 net::ClientSocketFactory::GetDefaultFactory();
Ryan Sleevi 2013/11/25 17:30:13 The "ideal" form is to pass this in as a variable
1032
1033 VLOG(1) << "SocketSecureFunction::Work: Creating TLS socket";
1034
1035 // Create the socket.
1036 ssl_socket_ = socket_factory->CreateSSLClientSocket(
1037 socket_handle.Pass(), host_port, ssl_config, context);
Ryan Sleevi 2013/11/25 17:30:13 BUG: This is broken, because you never connected |
Lally Singh 2013/12/05 17:07:12 I set it to underlying_socket above. That socket
1038
1039 VLOG(1) << "SocketSecureFunction::Work: Trying to connect";
1040 // And try to connect.
1041 int status = ssl_socket_->Connect(
1042 base::Bind(&SocketSecureFunction::TlsConnectDone, this));
1043 if (status != net::ERR_IO_PENDING) {
1044 TlsConnectDone(status);
Ryan Sleevi 2013/11/25 17:30:13 From an API point, this sort of async-or-recursion
Lally Singh 2013/12/05 17:07:12 I've added a comment on why this can't recurse int
1045 VLOG(1) << "SocketSecureFunction::Work: Done. ";
1046 } else {
1047 VLOG(1) << "SocketSecureFunction::Work: Returning, "
1048 << "but expecting a call to TlsConnectDone. ";
1049 }
1050 }
1051
1052 // Override the regular implementation, which would call AsyncWorkCompleted
1053 // immediately after Work().
1054 void SocketSecureFunction::AsyncWorkStart() {
1055 Work();
1056 }
1057
1058 void SocketSecureFunction::TlsConnectDone(int result) {
1059 SetResult(new base::FundamentalValue(result));
1060 VLOG(1) << "chrome.socket.secure: TlsConnectDone(): got back result "
1061 << result;
1062
1063 // No matter how the TLS connection attempt went, the underlying socket's
1064 // no longer bound to the original TCPSocket. It belongs to ssl_socket_,
1065 // which we either promote to a new API-accessible socket (via a TLSSocket
1066 // wrapper) or delete.
1067 if (result == net::OK) {
1068 // Wrap the StreamSocket in a TLSSocket (which matches our API). Set the
1069 // handle of the socket to the new value, so that we can use the newly
1070 // connected socket for close/SetKeepAlive/etc.
1071 TLSSocket* wrapper = new TLSSocket(
1072 ssl_socket_.release(), underlying_socket_, extension_->id());
1073
1074 // This deletes the old TCPSocket for us.
1075 SetSocket(params_->socket_id, wrapper);
1076 } else {
1077 // Failed TLS connection. This'll delete the underlying TCPClientSocket.
1078 ssl_socket_.reset();
1079 // This will delete the TCPSocket, which has already released its hold on
1080 // the TCPClientSocket.
1081 RemoveSocket(params_->socket_id);
1082 }
1083 AsyncWorkCompleted();
1084 }
1085
899 } // namespace extensions 1086 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698