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