| OLD | NEW |
| 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/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/platform_file.h" | 10 #include "base/platform_file.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 native_host_name_(native_host_name), | 102 native_host_name_(native_host_name), |
| 103 destination_port_(destination_port), | 103 destination_port_(destination_port), |
| 104 launcher_(launcher.Pass()), | 104 launcher_(launcher.Pass()), |
| 105 closed_(false), | 105 closed_(false), |
| 106 process_handle_(base::kNullProcessHandle), | 106 process_handle_(base::kNullProcessHandle), |
| 107 #if defined(OS_POSIX) | 107 #if defined(OS_POSIX) |
| 108 read_file_(base::kInvalidPlatformFileValue), | 108 read_file_(base::kInvalidPlatformFileValue), |
| 109 #endif | 109 #endif |
| 110 read_pending_(false), | 110 read_pending_(false), |
| 111 write_pending_(false) { | 111 write_pending_(false) { |
| 112 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 112 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 113 | 113 |
| 114 // It's safe to use base::Unretained() here because NativeMessagePort always | 114 // It's safe to use base::Unretained() here because NativeMessagePort always |
| 115 // deletes us on the IO thread. | 115 // deletes us on the IO thread. |
| 116 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, | 116 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, |
| 117 base::Bind(&NativeMessageProcessHost::LaunchHostProcess, | 117 base::Bind(&NativeMessageProcessHost::LaunchHostProcess, |
| 118 base::Unretained(this))); | 118 base::Unretained(this))); |
| 119 } | 119 } |
| 120 | 120 |
| 121 NativeMessageProcessHost::~NativeMessageProcessHost() { | 121 NativeMessageProcessHost::~NativeMessageProcessHost() { |
| 122 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 122 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 123 Close(std::string()); | 123 Close(std::string()); |
| 124 } | 124 } |
| 125 | 125 |
| 126 // static | 126 // static |
| 127 scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create( | 127 scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create( |
| 128 gfx::NativeView native_view, | 128 gfx::NativeView native_view, |
| 129 base::WeakPtr<Client> weak_client_ui, | 129 base::WeakPtr<Client> weak_client_ui, |
| 130 const std::string& source_extension_id, | 130 const std::string& source_extension_id, |
| 131 const std::string& native_host_name, | 131 const std::string& native_host_name, |
| 132 int destination_port, | 132 int destination_port, |
| 133 bool allow_user_level) { | 133 bool allow_user_level) { |
| 134 return CreateWithLauncher(weak_client_ui, source_extension_id, | 134 return CreateWithLauncher(weak_client_ui, source_extension_id, |
| 135 native_host_name, destination_port, | 135 native_host_name, destination_port, |
| 136 NativeProcessLauncher::CreateDefault( | 136 NativeProcessLauncher::CreateDefault( |
| 137 allow_user_level, native_view)); | 137 allow_user_level, native_view)); |
| 138 } | 138 } |
| 139 | 139 |
| 140 // static | 140 // static |
| 141 scoped_ptr<NativeMessageProcessHost> | 141 scoped_ptr<NativeMessageProcessHost> |
| 142 NativeMessageProcessHost::CreateWithLauncher( | 142 NativeMessageProcessHost::CreateWithLauncher( |
| 143 base::WeakPtr<Client> weak_client_ui, | 143 base::WeakPtr<Client> weak_client_ui, |
| 144 const std::string& source_extension_id, | 144 const std::string& source_extension_id, |
| 145 const std::string& native_host_name, | 145 const std::string& native_host_name, |
| 146 int destination_port, | 146 int destination_port, |
| 147 scoped_ptr<NativeProcessLauncher> launcher) { | 147 scoped_ptr<NativeProcessLauncher> launcher) { |
| 148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 148 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 149 | 149 |
| 150 scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost( | 150 scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost( |
| 151 weak_client_ui, source_extension_id, native_host_name, | 151 weak_client_ui, source_extension_id, native_host_name, |
| 152 destination_port, launcher.Pass())); | 152 destination_port, launcher.Pass())); |
| 153 | 153 |
| 154 return process.Pass(); | 154 return process.Pass(); |
| 155 } | 155 } |
| 156 | 156 |
| 157 void NativeMessageProcessHost::LaunchHostProcess() { | 157 void NativeMessageProcessHost::LaunchHostProcess() { |
| 158 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 158 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 159 | 159 |
| 160 GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_); | 160 GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_); |
| 161 launcher_->Launch(origin, native_host_name_, | 161 launcher_->Launch(origin, native_host_name_, |
| 162 base::Bind(&NativeMessageProcessHost::OnHostProcessLaunched, | 162 base::Bind(&NativeMessageProcessHost::OnHostProcessLaunched, |
| 163 base::Unretained(this))); | 163 base::Unretained(this))); |
| 164 } | 164 } |
| 165 | 165 |
| 166 void NativeMessageProcessHost::OnHostProcessLaunched( | 166 void NativeMessageProcessHost::OnHostProcessLaunched( |
| 167 NativeProcessLauncher::LaunchResult result, | 167 NativeProcessLauncher::LaunchResult result, |
| 168 base::ProcessHandle process_handle, | 168 base::ProcessHandle process_handle, |
| 169 base::File read_file, | 169 base::File read_file, |
| 170 base::File write_file) { | 170 base::File write_file) { |
| 171 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 171 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 172 | 172 |
| 173 switch (result) { | 173 switch (result) { |
| 174 case NativeProcessLauncher::RESULT_INVALID_NAME: | 174 case NativeProcessLauncher::RESULT_INVALID_NAME: |
| 175 Close(kInvalidNameError); | 175 Close(kInvalidNameError); |
| 176 return; | 176 return; |
| 177 case NativeProcessLauncher::RESULT_NOT_FOUND: | 177 case NativeProcessLauncher::RESULT_NOT_FOUND: |
| 178 Close(kNotFoundError); | 178 Close(kNotFoundError); |
| 179 return; | 179 return; |
| 180 case NativeProcessLauncher::RESULT_FORBIDDEN: | 180 case NativeProcessLauncher::RESULT_FORBIDDEN: |
| 181 Close(kForbiddenError); | 181 Close(kForbiddenError); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 205 write_stream_.reset(new net::FileStream( | 205 write_stream_.reset(new net::FileStream( |
| 206 write_file.TakePlatformFile(), | 206 write_file.TakePlatformFile(), |
| 207 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, NULL, | 207 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, NULL, |
| 208 task_runner)); | 208 task_runner)); |
| 209 | 209 |
| 210 WaitRead(); | 210 WaitRead(); |
| 211 DoWrite(); | 211 DoWrite(); |
| 212 } | 212 } |
| 213 | 213 |
| 214 void NativeMessageProcessHost::Send(const std::string& json) { | 214 void NativeMessageProcessHost::Send(const std::string& json) { |
| 215 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 215 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 216 | 216 |
| 217 if (closed_) | 217 if (closed_) |
| 218 return; | 218 return; |
| 219 | 219 |
| 220 // Allocate new buffer for the message. | 220 // Allocate new buffer for the message. |
| 221 scoped_refptr<net::IOBufferWithSize> buffer = | 221 scoped_refptr<net::IOBufferWithSize> buffer = |
| 222 new net::IOBufferWithSize(json.size() + kMessageHeaderSize); | 222 new net::IOBufferWithSize(json.size() + kMessageHeaderSize); |
| 223 | 223 |
| 224 // Copy size and content of the message to the buffer. | 224 // Copy size and content of the message to the buffer. |
| 225 COMPILE_ASSERT(sizeof(uint32) == kMessageHeaderSize, incorrect_header_size); | 225 COMPILE_ASSERT(sizeof(uint32) == kMessageHeaderSize, incorrect_header_size); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 #if defined(OS_POSIX) | 264 #if defined(OS_POSIX) |
| 265 base::MessageLoopForIO::current()->WatchFileDescriptor( | 265 base::MessageLoopForIO::current()->WatchFileDescriptor( |
| 266 read_file_, false /* persistent */, | 266 read_file_, false /* persistent */, |
| 267 base::MessageLoopForIO::WATCH_READ, &read_watcher_, this); | 267 base::MessageLoopForIO::WATCH_READ, &read_watcher_, this); |
| 268 #else // defined(OS_POSIX) | 268 #else // defined(OS_POSIX) |
| 269 DoRead(); | 269 DoRead(); |
| 270 #endif // defined(!OS_POSIX) | 270 #endif // defined(!OS_POSIX) |
| 271 } | 271 } |
| 272 | 272 |
| 273 void NativeMessageProcessHost::DoRead() { | 273 void NativeMessageProcessHost::DoRead() { |
| 274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 274 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 275 | 275 |
| 276 while (!closed_ && !read_pending_) { | 276 while (!closed_ && !read_pending_) { |
| 277 read_buffer_ = new net::IOBuffer(kReadBufferSize); | 277 read_buffer_ = new net::IOBuffer(kReadBufferSize); |
| 278 int result = read_stream_->Read( | 278 int result = read_stream_->Read( |
| 279 read_buffer_.get(), | 279 read_buffer_.get(), |
| 280 kReadBufferSize, | 280 kReadBufferSize, |
| 281 base::Bind(&NativeMessageProcessHost::OnRead, base::Unretained(this))); | 281 base::Bind(&NativeMessageProcessHost::OnRead, base::Unretained(this))); |
| 282 HandleReadResult(result); | 282 HandleReadResult(result); |
| 283 } | 283 } |
| 284 } | 284 } |
| 285 | 285 |
| 286 void NativeMessageProcessHost::OnRead(int result) { | 286 void NativeMessageProcessHost::OnRead(int result) { |
| 287 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 287 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 288 DCHECK(read_pending_); | 288 DCHECK(read_pending_); |
| 289 read_pending_ = false; | 289 read_pending_ = false; |
| 290 | 290 |
| 291 HandleReadResult(result); | 291 HandleReadResult(result); |
| 292 WaitRead(); | 292 WaitRead(); |
| 293 } | 293 } |
| 294 | 294 |
| 295 void NativeMessageProcessHost::HandleReadResult(int result) { | 295 void NativeMessageProcessHost::HandleReadResult(int result) { |
| 296 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 296 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 297 | 297 |
| 298 if (closed_) | 298 if (closed_) |
| 299 return; | 299 return; |
| 300 | 300 |
| 301 if (result > 0) { | 301 if (result > 0) { |
| 302 ProcessIncomingData(read_buffer_->data(), result); | 302 ProcessIncomingData(read_buffer_->data(), result); |
| 303 } else if (result == net::ERR_IO_PENDING) { | 303 } else if (result == net::ERR_IO_PENDING) { |
| 304 read_pending_ = true; | 304 read_pending_ = true; |
| 305 } else if (result == 0 || result == net::ERR_CONNECTION_RESET) { | 305 } else if (result == 0 || result == net::ERR_CONNECTION_RESET) { |
| 306 // On Windows we get net::ERR_CONNECTION_RESET for a broken pipe, while on | 306 // On Windows we get net::ERR_CONNECTION_RESET for a broken pipe, while on |
| 307 // Posix read() returns 0 in that case. | 307 // Posix read() returns 0 in that case. |
| 308 Close(kNativeHostExited); | 308 Close(kNativeHostExited); |
| 309 } else { | 309 } else { |
| 310 LOG(ERROR) << "Error when reading from Native Messaging host: " << result; | 310 LOG(ERROR) << "Error when reading from Native Messaging host: " << result; |
| 311 Close(kHostInputOuputError); | 311 Close(kHostInputOuputError); |
| 312 } | 312 } |
| 313 } | 313 } |
| 314 | 314 |
| 315 void NativeMessageProcessHost::ProcessIncomingData( | 315 void NativeMessageProcessHost::ProcessIncomingData( |
| 316 const char* data, int data_size) { | 316 const char* data, int data_size) { |
| 317 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 317 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 318 | 318 |
| 319 incoming_data_.append(data, data_size); | 319 incoming_data_.append(data, data_size); |
| 320 | 320 |
| 321 while (true) { | 321 while (true) { |
| 322 if (incoming_data_.size() < kMessageHeaderSize) | 322 if (incoming_data_.size() < kMessageHeaderSize) |
| 323 return; | 323 return; |
| 324 | 324 |
| 325 size_t message_size = | 325 size_t message_size = |
| 326 *reinterpret_cast<const uint32*>(incoming_data_.data()); | 326 *reinterpret_cast<const uint32*>(incoming_data_.data()); |
| 327 | 327 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 338 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 338 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 339 base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, | 339 base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, |
| 340 destination_port_, | 340 destination_port_, |
| 341 incoming_data_.substr(kMessageHeaderSize, message_size))); | 341 incoming_data_.substr(kMessageHeaderSize, message_size))); |
| 342 | 342 |
| 343 incoming_data_.erase(0, kMessageHeaderSize + message_size); | 343 incoming_data_.erase(0, kMessageHeaderSize + message_size); |
| 344 } | 344 } |
| 345 } | 345 } |
| 346 | 346 |
| 347 void NativeMessageProcessHost::DoWrite() { | 347 void NativeMessageProcessHost::DoWrite() { |
| 348 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 348 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 349 | 349 |
| 350 while (!write_pending_ && !closed_) { | 350 while (!write_pending_ && !closed_) { |
| 351 if (!current_write_buffer_.get() || | 351 if (!current_write_buffer_.get() || |
| 352 !current_write_buffer_->BytesRemaining()) { | 352 !current_write_buffer_->BytesRemaining()) { |
| 353 if (write_queue_.empty()) | 353 if (write_queue_.empty()) |
| 354 return; | 354 return; |
| 355 current_write_buffer_ = new net::DrainableIOBuffer( | 355 current_write_buffer_ = new net::DrainableIOBuffer( |
| 356 write_queue_.front().get(), write_queue_.front()->size()); | 356 write_queue_.front().get(), write_queue_.front()->size()); |
| 357 write_queue_.pop(); | 357 write_queue_.pop(); |
| 358 } | 358 } |
| 359 | 359 |
| 360 int result = | 360 int result = |
| 361 write_stream_->Write(current_write_buffer_.get(), | 361 write_stream_->Write(current_write_buffer_.get(), |
| 362 current_write_buffer_->BytesRemaining(), | 362 current_write_buffer_->BytesRemaining(), |
| 363 base::Bind(&NativeMessageProcessHost::OnWritten, | 363 base::Bind(&NativeMessageProcessHost::OnWritten, |
| 364 base::Unretained(this))); | 364 base::Unretained(this))); |
| 365 HandleWriteResult(result); | 365 HandleWriteResult(result); |
| 366 } | 366 } |
| 367 } | 367 } |
| 368 | 368 |
| 369 void NativeMessageProcessHost::HandleWriteResult(int result) { | 369 void NativeMessageProcessHost::HandleWriteResult(int result) { |
| 370 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 370 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 371 | 371 |
| 372 if (result <= 0) { | 372 if (result <= 0) { |
| 373 if (result == net::ERR_IO_PENDING) { | 373 if (result == net::ERR_IO_PENDING) { |
| 374 write_pending_ = true; | 374 write_pending_ = true; |
| 375 } else { | 375 } else { |
| 376 LOG(ERROR) << "Error when writing to Native Messaging host: " << result; | 376 LOG(ERROR) << "Error when writing to Native Messaging host: " << result; |
| 377 Close(kHostInputOuputError); | 377 Close(kHostInputOuputError); |
| 378 } | 378 } |
| 379 return; | 379 return; |
| 380 } | 380 } |
| 381 | 381 |
| 382 current_write_buffer_->DidConsume(result); | 382 current_write_buffer_->DidConsume(result); |
| 383 } | 383 } |
| 384 | 384 |
| 385 void NativeMessageProcessHost::OnWritten(int result) { | 385 void NativeMessageProcessHost::OnWritten(int result) { |
| 386 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 386 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 387 | 387 |
| 388 DCHECK(write_pending_); | 388 DCHECK(write_pending_); |
| 389 write_pending_ = false; | 389 write_pending_ = false; |
| 390 | 390 |
| 391 HandleWriteResult(result); | 391 HandleWriteResult(result); |
| 392 DoWrite(); | 392 DoWrite(); |
| 393 } | 393 } |
| 394 | 394 |
| 395 void NativeMessageProcessHost::Close(const std::string& error_message) { | 395 void NativeMessageProcessHost::Close(const std::string& error_message) { |
| 396 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 396 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 397 | 397 |
| 398 if (!closed_) { | 398 if (!closed_) { |
| 399 closed_ = true; | 399 closed_ = true; |
| 400 read_stream_.reset(); | 400 read_stream_.reset(); |
| 401 write_stream_.reset(); | 401 write_stream_.reset(); |
| 402 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 402 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 403 base::Bind(&Client::CloseChannel, weak_client_ui_, | 403 base::Bind(&Client::CloseChannel, weak_client_ui_, |
| 404 destination_port_, error_message)); | 404 destination_port_, error_message)); |
| 405 } | 405 } |
| 406 | 406 |
| 407 if (process_handle_ != base::kNullProcessHandle) { | 407 if (process_handle_ != base::kNullProcessHandle) { |
| 408 // Kill the host process if necessary to make sure we don't leave zombies. | 408 // Kill the host process if necessary to make sure we don't leave zombies. |
| 409 // On OSX base::EnsureProcessTerminated() may block, so we have to post a | 409 // On OSX base::EnsureProcessTerminated() may block, so we have to post a |
| 410 // task on the blocking pool. | 410 // task on the blocking pool. |
| 411 #if defined(OS_MACOSX) | 411 #if defined(OS_MACOSX) |
| 412 content::BrowserThread::PostBlockingPoolTask( | 412 content::BrowserThread::PostBlockingPoolTask( |
| 413 FROM_HERE, base::Bind(&base::EnsureProcessTerminated, process_handle_)); | 413 FROM_HERE, base::Bind(&base::EnsureProcessTerminated, process_handle_)); |
| 414 #else | 414 #else |
| 415 base::EnsureProcessTerminated(process_handle_); | 415 base::EnsureProcessTerminated(process_handle_); |
| 416 #endif | 416 #endif |
| 417 process_handle_ = base::kNullProcessHandle; | 417 process_handle_ = base::kNullProcessHandle; |
| 418 } | 418 } |
| 419 } | 419 } |
| 420 | 420 |
| 421 } // namespace extensions | 421 } // namespace extensions |
| OLD | NEW |