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"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/process/kill.h"
12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/threading/sequenced_worker_pool.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/features/feature.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"
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum message size in bytes for messages received from Native Messaging
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// hosts. Message size is limited mainly to prevent Chrome from crashing when
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// native application misbehaves (e.g. starts writing garbage to the pipe).
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaximumMessageSize = 1024 * 1024;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Message header contains 4-byte integer size of the message.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMessageHeaderSize = 4;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of the buffer to be allocated for each read.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kReadBufferSize = 4096;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kFailedToStartError[] = "Failed to start native messaging host.";
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidNameError[] =
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "Invalid native messaging host name specified.";
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kNativeHostExited[] = "Native host has exited.";
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNotFoundError[] = "Specified native messaging host not found.";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kForbiddenError[] =
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "Access to the specified native messaging host is forbidden.";
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHostInputOuputError[] =
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "Error when communicating with the native messaging host.";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NativeMessageProcessHost::PolicyPermission
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NativeMessageProcessHost::IsHostAllowed(const PrefService* pref_service,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const std::string& native_host_name) {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NativeMessageProcessHost::PolicyPermission allow_result = ALLOW_ALL;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service->IsManagedPreference(
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          pref_names::kNativeMessagingUserLevelHosts)) {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      allow_result = ALLOW_SYSTEM_ONLY;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // All native messaging hosts are allowed if there is no blacklist.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return allow_result;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::ListValue* blacklist =
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_service->GetList(pref_names::kNativeMessagingBlacklist);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!blacklist)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return allow_result;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check if the name or the wildcard is in the blacklist.
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::StringValue name_value(native_host_name);
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::StringValue wildcard_value("*");
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (blacklist->Find(name_value) == blacklist->end() &&
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blacklist->Find(wildcard_value) == blacklist->end()) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return allow_result;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The native messaging host is blacklisted. Check the whitelist.
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service->IsManagedPreference(
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          pref_names::kNativeMessagingWhitelist)) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* whitelist =
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pref_service->GetList(pref_names::kNativeMessagingWhitelist);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (whitelist && whitelist->Find(name_value) != whitelist->end())
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return allow_result;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return DISALLOW;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::NativeMessageProcessHost(
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<Client> weak_client_ui,
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& source_extension_id,
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& native_host_name,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int destination_port,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<NativeProcessLauncher> launcher)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : weak_client_ui_(weak_client_ui),
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      source_extension_id_(source_extension_id),
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      native_host_name_(native_host_name),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      destination_port_(destination_port),
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      launcher_(launcher.Pass()),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      closed_(false),
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      process_handle_(base::kNullProcessHandle),
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(OS_POSIX)
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      read_file_(-1),
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      read_pending_(false),
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      write_pending_(false) {
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It's safe to use base::Unretained() here because NativeMessagePort always
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // deletes us on the IO thread.
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NativeMessageProcessHost::LaunchHostProcess,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this)));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::~NativeMessageProcessHost() {
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Close(std::string());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create(
127ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    gfx::NativeView native_view,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<Client> weak_client_ui,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& source_extension_id,
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& native_host_name,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int destination_port,
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool allow_user_level) {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CreateWithLauncher(weak_client_ui, source_extension_id,
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            native_host_name, destination_port,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            NativeProcessLauncher::CreateDefault(
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                allow_user_level, native_view));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost>
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NativeMessageProcessHost::CreateWithLauncher(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<Client> weak_client_ui,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& source_extension_id,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& native_host_name,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int destination_port,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<NativeProcessLauncher> launcher) {
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost(
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      weak_client_ui, source_extension_id, native_host_name,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      destination_port, launcher.Pass()));
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return process.Pass();
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::LaunchHostProcess() {
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_);
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  launcher_->Launch(origin, native_host_name_,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    base::Bind(&NativeMessageProcessHost::OnHostProcessLaunched,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               base::Unretained(this)));
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnHostProcessLaunched(
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NativeProcessLauncher::LaunchResult result,
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::ProcessHandle process_handle,
16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    base::File read_file,
16923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    base::File write_file) {
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (result) {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NativeProcessLauncher::RESULT_INVALID_NAME:
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kInvalidNameError);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NativeProcessLauncher::RESULT_NOT_FOUND:
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kNotFoundError);
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NativeProcessLauncher::RESULT_FORBIDDEN:
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kForbiddenError);
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NativeProcessLauncher::RESULT_FAILED_TO_START:
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kFailedToStartError);
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NativeProcessLauncher::RESULT_SUCCESS:
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  process_handle_ = process_handle;
19023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(OS_POSIX)
19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // This object is not the owner of the file so it should not keep an fd.
19223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  read_file_ = read_file.GetPlatformFile();
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif
194ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
195ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_refptr<base::TaskRunner> task_runner(
196ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      content::BrowserThread::GetBlockingPool()->
197ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          GetTaskRunnerWithShutdownBehavior(
198ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch              base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
199ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  read_stream_.reset(new net::FileStream(read_file.Pass(), task_runner));
201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  write_stream_.reset(new net::FileStream(write_file.Pass(), task_runner));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitRead();
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoWrite();
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Send(const std::string& json) {
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (closed_)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Allocate new buffer for the message.
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::IOBufferWithSize> buffer =
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new net::IOBufferWithSize(json.size() + kMessageHeaderSize);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy size and content of the message to the buffer.
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  COMPILE_ASSERT(sizeof(uint32) == kMessageHeaderSize, incorrect_header_size);
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *reinterpret_cast<uint32*>(buffer->data()) = json.size();
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(buffer->data() + kMessageHeaderSize, json.data(), json.size());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Push new message to the write queue.
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  write_queue_.push(buffer);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send() may be called before the host process is started. In that case the
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // message will be written when OnHostProcessLaunched() is called. If it's
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // already started then write the message now.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (write_stream_)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoWrite();
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanReadWithoutBlocking(int fd) {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(fd, read_file_);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoRead();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanWriteWithoutBlocking(int fd) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // !defined(OS_POSIX)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ReadNowForTesting() {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoRead();
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::WaitRead() {
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (closed_)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!read_pending_);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // On POSIX FileStream::Read() uses blocking thread pool, so it's better to
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // wait for the file to become readable before calling DoRead(). Otherwise it
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // would always be consuming one thread in the thread pool. On Windows
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // FileStream uses overlapped IO, so that optimization isn't necessary there.
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX)
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoopForIO::current()->WatchFileDescriptor(
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    read_file_, false /* persistent */,
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    base::MessageLoopForIO::WATCH_READ, &read_watcher_, this);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else  // defined(OS_POSIX)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoRead();
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // defined(!OS_POSIX)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoRead() {
267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  while (!closed_ && !read_pending_) {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    read_buffer_ = new net::IOBuffer(kReadBufferSize);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int result = read_stream_->Read(
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        read_buffer_.get(),
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kReadBufferSize,
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        base::Bind(&NativeMessageProcessHost::OnRead, base::Unretained(this)));
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HandleReadResult(result);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnRead(int result) {
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(read_pending_);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  read_pending_ = false;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HandleReadResult(result);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitRead();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleReadResult(int result) {
289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (closed_)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result > 0) {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ProcessIncomingData(read_buffer_->data(), result);
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (result == net::ERR_IO_PENDING) {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    read_pending_ = true;
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else if (result == 0 || result == net::ERR_CONNECTION_RESET) {
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // On Windows we get net::ERR_CONNECTION_RESET for a broken pipe, while on
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Posix read() returns 0 in that case.
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Close(kNativeHostExited);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Error when reading from Native Messaging host: " << result;
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Close(kHostInputOuputError);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ProcessIncomingData(
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const char* data, int data_size) {
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  incoming_data_.append(data, data_size);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (true) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (incoming_data_.size() < kMessageHeaderSize)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t message_size =
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *reinterpret_cast<const uint32*>(incoming_data_.data());
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (message_size > kMaximumMessageSize) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Native Messaging host tried sending a message that is "
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << message_size << " bytes long.";
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kHostInputOuputError);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (incoming_data_.size() < message_size + kMessageHeaderSize)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_,
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            destination_port_,
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            incoming_data_.substr(kMessageHeaderSize, message_size)));
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    incoming_data_.erase(0, kMessageHeaderSize + message_size);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoWrite() {
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!write_pending_ && !closed_) {
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!current_write_buffer_.get() ||
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        !current_write_buffer_->BytesRemaining()) {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (write_queue_.empty())
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_write_buffer_ = new net::DrainableIOBuffer(
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          write_queue_.front().get(), write_queue_.front()->size());
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      write_queue_.pop();
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int result =
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        write_stream_->Write(current_write_buffer_.get(),
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             current_write_buffer_->BytesRemaining(),
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             base::Bind(&NativeMessageProcessHost::OnWritten,
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                        base::Unretained(this)));
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HandleWriteResult(result);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleWriteResult(int result) {
363effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result <= 0) {
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (result == net::ERR_IO_PENDING) {
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      write_pending_ = true;
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Error when writing to Native Messaging host: " << result;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Close(kHostInputOuputError);
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  current_write_buffer_->DidConsume(result);
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnWritten(int result) {
379effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(write_pending_);
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  write_pending_ = false;
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HandleWriteResult(result);
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoWrite();
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Close(const std::string& error_message) {
389effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!closed_) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closed_ = true;
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    read_stream_.reset();
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    write_stream_.reset();
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&Client::CloseChannel, weak_client_ui_,
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   destination_port_, error_message));
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (process_handle_ != base::kNullProcessHandle) {
4014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Kill the host process if necessary to make sure we don't leave zombies.
4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // On OSX base::EnsureProcessTerminated() may block, so we have to post a
4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // task on the blocking pool.
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_MACOSX)
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::BrowserThread::PostBlockingPoolTask(
4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE, base::Bind(&base::EnsureProcessTerminated, process_handle_));
4074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#else
4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::EnsureProcessTerminated(process_handle_);
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    process_handle_ = base::kNullProcessHandle;
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
415