native_message_process_host.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_message_process_host.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/bind_helpers.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/json/json_reader.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/platform_file.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_process_launcher.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/features/feature.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "googleurl/src/gurl.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/file_stream.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_util.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum message size in bytes for messages received from Native Messaging 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// hosts. Message size is limited mainly to prevent Chrome from crashing when 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// native application misbehaves (e.g. starts writing garbage to the pipe). 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaximumMessageSize = 1024 * 1024; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Message header contains 4-byte integer size of the message. 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMessageHeaderSize = 4; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of the buffer to be allocated for each read. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kReadBufferSize = 4096; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kFailedToStartError[] = "Failed to start native messaging host."; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidNameError[] = 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid native messaging host name specified."; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNotFoundError[] = "Specified native messaging host not found."; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kForbiddenError[] = 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Access to the specified native messaging host is forbidden."; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHostInputOuputError[] = 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Error when communicating with the native messaging host."; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kInvalidJsonError[] = 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "Message must be valid JSON"; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::NativeMessageProcessHost( 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int destination_port, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeProcessLauncher> launcher) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : weak_client_ui_(weak_client_ui), 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source_extension_id_(source_extension_id), 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) native_host_name_(native_host_name), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) destination_port_(destination_port), 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_(launcher.Pass()), 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_(false), 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_(false), 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_eof_(false), 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_(false) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It's safe to use base::Unretained() here because NativeMessagePort always 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // deletes us on the IO thread. 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&NativeMessageProcessHost::LaunchHostProcess, 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::~NativeMessageProcessHost() { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(std::string()); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create( 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int destination_port) { 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return CreateWithLauncher(weak_client_ui, source_extension_id, 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) native_host_name, destination_port, 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NativeProcessLauncher::CreateDefault()); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost> 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NativeMessageProcessHost::CreateWithLauncher( 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int destination_port, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeProcessLauncher> launcher) { 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost( 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_client_ui, source_extension_id, native_host_name, 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port, launcher.Pass())); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return process.Pass(); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::LaunchHostProcess() { 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_); 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_->Launch(origin, native_host_name_, 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnHostProcessLaunched, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnHostProcessLaunched( 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NativeProcessLauncher::LaunchResult result, 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PlatformFile read_file, 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PlatformFile write_file) { 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (result) { 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_INVALID_NAME: 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kInvalidNameError); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_NOT_FOUND: 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kNotFoundError); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_FORBIDDEN: 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kForbiddenError); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_FAILED_TO_START: 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kFailedToStartError); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_SUCCESS: 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_file_ = read_file; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_stream_.reset(new net::FileStream( 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_file, base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC, NULL)); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_stream_.reset(new net::FileStream( 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_file, base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, NULL)); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WaitRead(); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Send(const std::string& json) { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (closed_) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Allocate new buffer for the message. 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<net::IOBufferWithSize> buffer = 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new net::IOBufferWithSize(json.size() + kMessageHeaderSize); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Copy size and content of the message to the buffer. 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(sizeof(uint32) == kMessageHeaderSize, incorrect_header_size); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *reinterpret_cast<uint32*>(buffer->data()) = json.size(); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memcpy(buffer->data() + kMessageHeaderSize, json.data(), json.size()); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Push new message to the write queue. 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_queue_.push(buffer); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Send() may be called before the host process is started. In that case the 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // message will be written when OnHostProcessLaunched() is called. If it's 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // already started then write the message now. 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (write_stream_) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanReadWithoutBlocking(int fd) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(fd, read_file_); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanWriteWithoutBlocking(int fd) { 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // !defined(OS_POSIX) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ReadNowForTesting() { 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::WaitRead() { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (closed_ || read_eof_) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!read_pending_); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // On POSIX FileStream::Read() uses blocking thread pool, so it's better to 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // wait for the file to become readable before calling DoRead(). Otherwise it 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // would always be consuming one thread in the thread pool. On Windows 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // FileStream uses overlapped IO, so that optimization isn't necessary there. 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoopForIO::current()->WatchFileDescriptor( 20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) read_file_, false /* persistent */, base::MessageLoopForIO::WATCH_READ, 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &read_watcher_, this); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else // defined(OS_POSIX) 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // defined(!OS_POSIX) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoRead() { 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!closed_ && !read_eof_ && !read_pending_) { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_buffer_ = new net::IOBuffer(kReadBufferSize); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int result = read_stream_->Read( 218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) read_buffer_.get(), 219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kReadBufferSize, 220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnRead, base::Unretained(this))); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleReadResult(result); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnRead(int result) { 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(read_pending_); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_ = false; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleReadResult(result); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WaitRead(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleReadResult(int result) { 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (closed_) 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result > 0) { 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcessIncomingData(read_buffer_->data(), result); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (result == 0) { 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_eof_ = true; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (result == net::ERR_IO_PENDING) { 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_ = true; 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Error when reading from Native Messaging host: " << result; 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ProcessIncomingData( 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* data, int data_size) { 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) incoming_data_.append(data, data_size); 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (true) { 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming_data_.size() < kMessageHeaderSize) 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t message_size = 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *reinterpret_cast<const uint32*>(incoming_data_.data()); 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (message_size > kMaximumMessageSize) { 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Native Messaging host tried sending a message that is " 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << message_size << " bytes long."; 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming_data_.size() < message_size + kMessageHeaderSize) 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<base::ListValue> message(new base::ListValue()); 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) { 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string message_as_json = 278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) incoming_data_.substr(kMessageHeaderSize, message_size); 279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int error_code; 280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string error_message; 281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<base::Value> message_as_value( 282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::JSONReader::ReadAndReturnError(message_as_json, 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0, // no flags 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &error_code, 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &error_message)); 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!message_as_value) { 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::JSONReader::JsonParseError parse_error = 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<base::JSONReader::JsonParseError>(error_code); 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG(ERROR) << "Native Messaging host sent message with invalid JSON \"" 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) << message_as_json << "\": " << error_message << " (" 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) << base::JSONReader::ErrorCodeToString(parse_error) << "), " 292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) << "message size " << message_size << ", " 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) << "incoming data size " << incoming_data_.size() << "."; 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Close(kInvalidJsonError); 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) message->Append(message_as_value.release()); 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port_, 303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Passed(&message))); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) incoming_data_.erase(0, kMessageHeaderSize + message_size); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoWrite() { 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!write_pending_ && !closed_) { 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!current_write_buffer_.get() || 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) !current_write_buffer_->BytesRemaining()) { 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (write_queue_.empty()) 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_write_buffer_ = new net::DrainableIOBuffer( 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_queue_.front().get(), write_queue_.front()->size()); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_queue_.pop(); 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int result = 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_stream_->Write(current_write_buffer_.get(), 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) current_write_buffer_->BytesRemaining(), 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnWritten, 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Unretained(this))); 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleWriteResult(result); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleWriteResult(int result) { 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result <= 0) { 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result == net::ERR_IO_PENDING) { 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_ = true; 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Error when writing to Native Messaging host: " << result; 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_write_buffer_->DidConsume(result); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnWritten(int result) { 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(write_pending_); 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_ = false; 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleWriteResult(result); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Close(const std::string& error_message) { 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!closed_) { 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_ = true; 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_stream_.reset(); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_stream_.reset(); 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&Client::CloseChannel, weak_client_ui_, 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port_, error_message)); 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 371