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

Side by Side Diff: chrome/browser/extensions/api/messaging/native_message_process_host.cc

Issue 10918255: The Windows portion of Native Messagaing (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 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
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/messaging/native_message_process_host.h" 5 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/path_service.h" 10 #include "base/path_service.h"
11 #include "base/pickle.h" 11 #include "base/pickle.h"
12 #include "base/process_util.h" 12 #include "base/process_util.h"
13 #include "base/values.h" 13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h" 14 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
15 #include "chrome/common/chrome_paths.h" 15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/chrome_version_info.h" 17 #include "chrome/common/chrome_version_info.h"
18 #include "chrome/common/extensions/features/feature.h" 18 #include "chrome/common/extensions/features/feature.h"
19 #include "content/public/common/result_codes.h" 19 #include "content/public/common/result_codes.h"
20 20
21 namespace { 21 namespace {
22 22
23 const int kExitTimeoutMS = 5000;
24 const uint32 kMaxMessageDataLength = 10 * 1024 * 1024;
25 const char kNativeHostsDirectoryName[] = "Native Hosts"; 23 const char kNativeHostsDirectoryName[] = "Native Hosts";
26 24
27 } // namespace 25 } // namespace
28 26
29 namespace extensions { 27 namespace extensions {
30 28
29 // static
30 const int NativeMessageProcessHost::kExitTimeoutMS = 5000;
31 const uint32 NativeMessageProcessHost::kMaxMessageDataLength = 10 * 1024 * 1024;
32
31 NativeMessageProcessHost::NativeMessageProcessHost( 33 NativeMessageProcessHost::NativeMessageProcessHost(
32 base::WeakPtr<Client> weak_client_ui, 34 base::WeakPtr<Client> weak_client_ui,
33 int destination_port, 35 int destination_port,
34 base::ProcessHandle native_process_handle, 36 base::ProcessHandle native_process_handle,
35 FileHandle read_file, 37 FileHandle read_file,
36 FileHandle write_file, 38 FileHandle write_file,
37 bool is_send_message) 39 bool is_send_message)
38 : weak_client_ui_(weak_client_ui), 40 : weak_client_ui_(weak_client_ui),
39 destination_port_(destination_port), 41 destination_port_(destination_port),
40 native_process_handle_(native_process_handle), 42 native_process_handle_(native_process_handle),
41 read_file_(read_file), 43 read_file_(read_file),
42 write_file_(write_file), 44 write_file_(write_file),
43 scoped_read_file_(&read_file_), 45 scoped_read_file_(&read_file_),
44 scoped_write_file_(&write_file_), 46 scoped_write_file_(&write_file_),
45 is_send_message_(is_send_message) { 47 is_send_message_(is_send_message) {
46 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 48 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
47 InitIO(); 49 InitIO();
48 } 50 }
49 51
50 NativeMessageProcessHost::~NativeMessageProcessHost() { 52 NativeMessageProcessHost::~NativeMessageProcessHost() {
51 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 53 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
54
55 StopIO();
56
52 // Give the process some time to shutdown, then try and kill it. 57 // Give the process some time to shutdown, then try and kill it.
53 content::BrowserThread::PostDelayedTask( 58 if (native_process_handle_ != base::kNullProcessHandle &&
54 content::BrowserThread::FILE, 59 base::GetTerminationStatus(native_process_handle_, NULL) ==
55 FROM_HERE, 60 base::TERMINATION_STATUS_STILL_RUNNING) {
56 base::Bind(base::IgnoreResult(&base::KillProcess), 61 content::BrowserThread::PostDelayedTask(
57 native_process_handle_, 62 content::BrowserThread::IO,
58 content::RESULT_CODE_NORMAL_EXIT, 63 FROM_HERE,
59 false /* don't wait for exit */), 64 base::Bind(base::IgnoreResult(&base::KillProcess),
60 base::TimeDelta::FromMilliseconds(kExitTimeoutMS)); 65 native_process_handle_,
66 content::RESULT_CODE_NORMAL_EXIT,
67 true /* wait for exit */),
68 base::TimeDelta::FromMilliseconds(kExitTimeoutMS));
69 }
61 } 70 }
62 71
63 // static 72 // static
64 void NativeMessageProcessHost::Create(base::WeakPtr<Client> weak_client_ui, 73 void NativeMessageProcessHost::Create(base::WeakPtr<Client> weak_client_ui,
65 const std::string& native_app_name, 74 const std::string& native_app_name,
66 const std::string& connection_message, 75 const std::string& connection_message,
67 int destination_port, 76 int destination_port,
68 MessageType type, 77 MessageType type,
69 CreateCallback callback) { 78 CreateCallback callback) {
70 NativeProcessLauncher launcher;
71 CreateWithLauncher(weak_client_ui, native_app_name, connection_message, 79 CreateWithLauncher(weak_client_ui, native_app_name, connection_message,
72 destination_port, type, callback, launcher); 80 destination_port, type, callback,
81 scoped_ptr<NativeProcessLauncher>(
82 new NativeProcessLauncher()));
73 } 83 }
74 84
75 // static 85 // static
76 void NativeMessageProcessHost::CreateWithLauncher( 86 void NativeMessageProcessHost::CreateWithLauncher(
77 base::WeakPtr<Client> weak_client_ui, 87 base::WeakPtr<Client> weak_client_ui,
78 const std::string& native_app_name, 88 const std::string& native_app_name,
79 const std::string& connection_message, 89 const std::string& connection_message,
80 int destination_port, 90 int destination_port,
81 MessageType type, 91 MessageType type,
82 CreateCallback callback, 92 CreateCallback callback,
83 const NativeProcessLauncher& launcher) { 93 scoped_ptr<NativeProcessLauncher> launcher) {
84 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 94 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
85 DCHECK(type == TYPE_SEND_MESSAGE_REQUEST || type == TYPE_CONNECT); 95 DCHECK(type == TYPE_SEND_MESSAGE_REQUEST || type == TYPE_CONNECT);
86 96
87 ScopedHost process; 97 ScopedHost process;
88 if (Feature::GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV || 98 if (Feature::GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV ||
89 !CommandLine::ForCurrentProcess()->HasSwitch( 99 !CommandLine::ForCurrentProcess()->HasSwitch(
90 switches::kEnableNativeMessaging)) { 100 switches::kEnableNativeMessaging)) {
91 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 101 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
92 base::Bind(callback, 102 base::Bind(callback,
93 base::Passed(&process))); 103 base::Passed(&process)));
94 return; 104 return;
95 } 105 }
96 106
107 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
108 base::Bind(&NativeMessageProcessHost::LaunchProcessOnFileThread,
109 weak_client_ui,
110 native_app_name,
111 connection_message,
112 destination_port,
113 type,
114 callback,
115 base::Passed(&launcher)));
116 }
117
118 // static
119 void NativeMessageProcessHost::LaunchProcessOnFileThread(
120 base::WeakPtr<Client> weak_client_ui,
121 const std::string& native_app_name,
122 const std::string& connection_message,
123 int destination_port,
124 MessageType type,
125 CreateCallback callback,
126 scoped_ptr<NativeProcessLauncher> launcher) {
127 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
128 ScopedHost process;
97 FilePath native_host_program; 129 FilePath native_host_program;
98 FilePath native_host_registry; 130 FilePath native_host_registry;
99 CHECK(PathService::Get(chrome::DIR_USER_DATA, &native_host_registry)); 131 CHECK(PathService::Get(chrome::DIR_USER_DATA, &native_host_registry));
100 native_host_registry = 132 native_host_registry =
101 native_host_registry.AppendASCII(kNativeHostsDirectoryName); 133 native_host_registry.AppendASCII(kNativeHostsDirectoryName);
102 native_host_program = native_host_registry.AppendASCII(native_app_name); 134 native_host_program = native_host_registry.AppendASCII(native_app_name);
103 135
104 // Make sure that the client is not trying to invoke something outside of the 136 // Make sure that the client is not trying to invoke something outside of the
105 // proper directory. Eg. '../../dangerous_something.exe'. 137 // proper directory. Eg. '../../dangerous_something.exe'.
106 if (!file_util::ContainsPath(native_host_registry, native_host_program)) { 138 if (!file_util::ContainsPath(native_host_registry, native_host_program)) {
107 LOG(ERROR) << "Could not find native host: " << native_app_name; 139 LOG(ERROR) << "Could not find native host: " << native_app_name;
108 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 140 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
109 base::Bind(callback, 141 base::Bind(callback,
110 base::Passed(&process))); 142 base::Passed(&process)));
111 return; 143 return;
112 } 144 }
113 145
114 FileHandle read_handle; 146 FileHandle read_handle;
115 FileHandle write_handle; 147 FileHandle write_handle;
116 base::ProcessHandle native_process_handle; 148 base::ProcessHandle native_process_handle;
117 149
118 if (!launcher.LaunchNativeProcess(native_host_program, 150 if (!launcher->LaunchNativeProcess(native_host_program,
119 &native_process_handle, 151 &native_process_handle,
120 &read_handle, 152 &read_handle,
121 &write_handle)) { 153 &write_handle)) {
122 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 154 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
123 base::Bind(callback, 155 base::Bind(callback,
124 base::Passed(&process))); 156 base::Passed(&process)));
125 return; 157 return;
126 } 158 }
127 159
160 NativeProcessHostCreationInformation creation_info(weak_client_ui,
161 connection_message,
162 destination_port,
163 type,
164 callback,
165 read_handle,
166 write_handle,
167 native_process_handle);
168
169 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
170 base::Bind(&NativeMessageProcessHost::FinalizeCreate,
171 creation_info));
172 }
173
174 // static
175 void NativeMessageProcessHost::FinalizeCreate(
176 NativeProcessHostCreationInformation creation_info) {
177 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
178 ScopedHost process;
179
128 process.reset(new NativeMessageProcessHost( 180 process.reset(new NativeMessageProcessHost(
129 weak_client_ui, destination_port, native_process_handle, read_handle, 181 creation_info.weak_client_ui, creation_info.destination_port,
130 write_handle, type == TYPE_SEND_MESSAGE_REQUEST)); 182 creation_info.native_process_handle, creation_info.read_handle,
183 creation_info.write_handle,
184 creation_info.type == TYPE_SEND_MESSAGE_REQUEST));
131 185
132 process->SendImpl(type, connection_message); 186 process->SendImpl(creation_info.type, creation_info.connection_message);
133 187
134 content::BrowserThread::PostTask( 188 content::BrowserThread::PostTask(
135 content::BrowserThread::UI, FROM_HERE, 189 content::BrowserThread::UI, FROM_HERE,
136 base::Bind(callback, base::Passed(&process))); 190 base::Bind(creation_info.callback, base::Passed(&process)));
137 } 191 }
138 192
139 void NativeMessageProcessHost::SendImpl(MessageType type, 193 void NativeMessageProcessHost::SendImpl(MessageType type,
140 const std::string& json) { 194 const std::string& json) {
141 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 195 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
142 196
143 // Make sure that the process has not died. 197 // Make sure that the process has not died.
144 if (base::GetTerminationStatus(native_process_handle_, NULL) != 198 if (native_process_handle_ != base::kNullProcessHandle &&
145 base::TERMINATION_STATUS_STILL_RUNNING) { 199 base::GetTerminationStatus(native_process_handle_, NULL) !=
200 base::TERMINATION_STATUS_STILL_RUNNING) {
146 // Notify the message service that the channel should close. 201 // Notify the message service that the channel should close.
147 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 202 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
148 base::Bind(&Client::CloseChannel, weak_client_ui_, 203 base::Bind(&Client::CloseChannel, weak_client_ui_,
149 destination_port_, true)); 204 destination_port_, true));
150 } 205 }
151 206
152 WriteMessage(type, json); 207 WriteMessage(type, json);
153 } 208 }
154 209
155 bool NativeMessageProcessHost::WriteMessage(MessageType type, 210 bool NativeMessageProcessHost::WriteMessage(MessageType type,
(...skipping 11 matching lines...) Expand all
167 222
168 if (!WriteData(write_file_, const_cast<const Pickle*>(&pickle)->payload(), 223 if (!WriteData(write_file_, const_cast<const Pickle*>(&pickle)->payload(),
169 pickle.payload_size())) { 224 pickle.payload_size())) {
170 LOG(ERROR) << "Error writing message to the native client."; 225 LOG(ERROR) << "Error writing message to the native client.";
171 return false; 226 return false;
172 } 227 }
173 228
174 return true; 229 return true;
175 } 230 }
176 231
177 bool NativeMessageProcessHost::ReadMessage(MessageType* type, 232 bool NativeMessageProcessHost::VerifyMessageMetaData(
178 std::string* message) { 233 const char* message_meta_data,
179 // Read the type (uint32) and length (uint32). 234 MessageType* type,
180 char message_meta_data[8]; 235 uint32* message_length) {
181 if (!ReadData(read_file_, message_meta_data, 8)) {
182 LOG(ERROR) << "Error reading the message type and length.";
183 return false;
184 }
185
186 Pickle pickle; 236 Pickle pickle;
187 pickle.WriteBytes(message_meta_data, 8); 237 pickle.WriteBytes(message_meta_data, 8);
188 PickleIterator pickle_it(pickle); 238 PickleIterator pickle_it(pickle);
189 uint32 uint_type; 239 uint32 uint_type;
190 uint32 data_length; 240 uint32 data_length;
191 if (!pickle_it.ReadUInt32(&uint_type) || 241 if (!pickle_it.ReadUInt32(&uint_type) ||
192 !pickle_it.ReadUInt32(&data_length)) { 242 !pickle_it.ReadUInt32(&data_length)) {
193 LOG(ERROR) << "Error getting the message type and length from the pickle."; 243 LOG(ERROR) << "Error getting the message type and length from the pickle.";
194 return false; 244 return false;
195 } 245 }
196 246
197 if (uint_type >= NUM_MESSAGE_TYPES) { 247 if (uint_type >= NUM_MESSAGE_TYPES) {
198 LOG(ERROR) << type << " is not a valid message type."; 248 LOG(ERROR) << type << " is not a valid message type.";
199 return false; 249 return false;
200 } 250 }
201 251
202 if ((is_send_message_ && (uint_type != TYPE_SEND_MESSAGE_RESPONSE)) || 252 if ((is_send_message_ && (uint_type != TYPE_SEND_MESSAGE_RESPONSE)) ||
203 (!is_send_message_ && (uint_type != TYPE_CONNECT_MESSAGE))) { 253 (!is_send_message_ && (uint_type != TYPE_CONNECT_MESSAGE))) {
204 LOG(ERROR) << "Recieved a message of type " << uint_type << ". " 254 LOG(ERROR) << "Recieved a message of type " << uint_type << ". "
205 << "Expecting a message of type " 255 << "Expecting a message of type "
206 << (is_send_message_ ? TYPE_SEND_MESSAGE_RESPONSE : 256 << (is_send_message_ ? TYPE_SEND_MESSAGE_RESPONSE :
207 TYPE_CONNECT_MESSAGE); 257 TYPE_CONNECT_MESSAGE);
208 return false; 258 return false;
209 } 259 }
210 *type = static_cast<MessageType>(uint_type);
211 260
212 if (data_length > kMaxMessageDataLength) { 261 if (data_length > kMaxMessageDataLength) {
213 LOG(ERROR) << data_length << " is too large for the length of a message. " 262 LOG(ERROR) << data_length << " is too large for the length of a message. "
214 << "Max message size is " << kMaxMessageDataLength; 263 << "Max message size is " << kMaxMessageDataLength;
215 return false; 264 return false;
216 } 265 }
217 266
218 message->resize(data_length, '\0'); 267 *type = static_cast<MessageType>(uint_type);
219 if (!ReadData(read_file_, &(*message)[0], data_length)) { 268 *message_length = data_length;
220 LOG(ERROR) << "Error reading the json data.";
221 return false;
222 }
223 269
224 return true; 270 return true;
225 } 271 }
226 272
227 } // namespace extensions 273 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698