Revert 285173 "Removed InProcessBrowserTest::CleanUpOnMainThread()"
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / native_process_launcher.cc
blob829c4df79cedf85b6eee4ebf9fad0d8d9b20515c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "url/gurl.h"
23 #if defined(OS_WIN)
24 #include "ui/views/win/hwnd_util.h"
25 #endif
27 namespace extensions {
29 namespace {
31 #if defined(OS_WIN)
32 // Name of the command line switch used to pass handle of the native view to
33 // the native messaging host.
34 const char kParentWindowSwitchName[] = "parent-window";
35 #endif // defined(OS_WIN)
37 // Default implementation on NativeProcessLauncher interface.
38 class NativeProcessLauncherImpl : public NativeProcessLauncher {
39 public:
40 NativeProcessLauncherImpl(bool allow_user_level_hosts,
41 intptr_t native_window);
42 virtual ~NativeProcessLauncherImpl();
44 virtual void Launch(const GURL& origin,
45 const std::string& native_host_name,
46 LaunchedCallback callback) const OVERRIDE;
48 private:
49 class Core : public base::RefCountedThreadSafe<Core> {
50 public:
51 Core(bool allow_user_level_hosts, intptr_t native_window);
52 void Launch(const GURL& origin,
53 const std::string& native_host_name,
54 LaunchedCallback callback);
55 void Detach();
57 private:
58 friend class base::RefCountedThreadSafe<Core>;
59 virtual ~Core();
61 void DoLaunchOnThreadPool(const GURL& origin,
62 const std::string& native_host_name,
63 LaunchedCallback callback);
64 void PostErrorResult(const LaunchedCallback& callback, LaunchResult error);
65 void PostResult(const LaunchedCallback& callback,
66 base::ProcessHandle process_handle,
67 base::File read_file,
68 base::File write_file);
69 void CallCallbackOnIOThread(LaunchedCallback callback,
70 LaunchResult result,
71 base::ProcessHandle process_handle,
72 base::File read_file,
73 base::File write_file);
75 bool detached_;
77 bool allow_user_level_hosts_;
79 // Handle of the native window corresponding to the extension.
80 intptr_t window_handle_;
82 DISALLOW_COPY_AND_ASSIGN(Core);
85 scoped_refptr<Core> core_;
87 DISALLOW_COPY_AND_ASSIGN(NativeProcessLauncherImpl);
90 NativeProcessLauncherImpl::Core::Core(bool allow_user_level_hosts,
91 intptr_t window_handle)
92 : detached_(false),
93 allow_user_level_hosts_(allow_user_level_hosts),
94 window_handle_(window_handle) {
97 NativeProcessLauncherImpl::Core::~Core() {
98 DCHECK(detached_);
101 void NativeProcessLauncherImpl::Core::Detach() {
102 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
103 detached_ = true;
106 void NativeProcessLauncherImpl::Core::Launch(
107 const GURL& origin,
108 const std::string& native_host_name,
109 LaunchedCallback callback) {
110 content::BrowserThread::PostBlockingPoolTask(
111 FROM_HERE, base::Bind(&Core::DoLaunchOnThreadPool, this,
112 origin, native_host_name, callback));
115 void NativeProcessLauncherImpl::Core::DoLaunchOnThreadPool(
116 const GURL& origin,
117 const std::string& native_host_name,
118 LaunchedCallback callback) {
119 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
121 if (!NativeMessagingHostManifest::IsValidName(native_host_name)) {
122 PostErrorResult(callback, RESULT_INVALID_NAME);
123 return;
126 std::string error_message;
127 base::FilePath manifest_path =
128 FindManifest(native_host_name, allow_user_level_hosts_, &error_message);
130 if (manifest_path.empty()) {
131 LOG(ERROR) << "Can't find manifest for native messaging host "
132 << native_host_name;
133 PostErrorResult(callback, RESULT_NOT_FOUND);
134 return;
137 scoped_ptr<NativeMessagingHostManifest> manifest =
138 NativeMessagingHostManifest::Load(manifest_path, &error_message);
140 if (!manifest) {
141 LOG(ERROR) << "Failed to load manifest for native messaging host "
142 << native_host_name << ": " << error_message;
143 PostErrorResult(callback, RESULT_NOT_FOUND);
144 return;
147 if (manifest->name() != native_host_name) {
148 LOG(ERROR) << "Failed to load manifest for native messaging host "
149 << native_host_name
150 << ": Invalid name specified in the manifest.";
151 PostErrorResult(callback, RESULT_NOT_FOUND);
152 return;
155 if (!manifest->allowed_origins().MatchesSecurityOrigin(origin)) {
156 // Not an allowed origin.
157 PostErrorResult(callback, RESULT_FORBIDDEN);
158 return;
161 base::FilePath host_path = manifest->path();
162 if (!host_path.IsAbsolute()) {
163 // On Windows host path is allowed to be relative to the location of the
164 // manifest file. On all other platforms the path must be absolute.
165 #if defined(OS_WIN)
166 host_path = manifest_path.DirName().Append(host_path);
167 #else // defined(OS_WIN)
168 LOG(ERROR) << "Native messaging host path must be absolute for "
169 << native_host_name;
170 PostErrorResult(callback, RESULT_NOT_FOUND);
171 return;
172 #endif // !defined(OS_WIN)
175 // In case when the manifest file is there, but the host binary doesn't exist
176 // report the NOT_FOUND error.
177 if (!base::PathExists(host_path)) {
178 LOG(ERROR)
179 << "Found manifest, but not the binary for native messaging host "
180 << native_host_name << ". Host path specified in the manifest: "
181 << host_path.AsUTF8Unsafe();
182 PostErrorResult(callback, RESULT_NOT_FOUND);
183 return;
186 CommandLine command_line(host_path);
187 command_line.AppendArg(origin.spec());
189 // Pass handle of the native view window to the native messaging host. This
190 // way the host will be able to create properly focused UI windows.
191 #if defined(OS_WIN)
192 command_line.AppendSwitchASCII(kParentWindowSwitchName,
193 base::Int64ToString(window_handle_));
194 #endif // !defined(OS_WIN)
196 base::ProcessHandle process_handle;
197 base::File read_file;
198 base::File write_file;
199 if (NativeProcessLauncher::LaunchNativeProcess(
200 command_line, &process_handle, &read_file, &write_file)) {
201 PostResult(callback, process_handle, read_file.Pass(), write_file.Pass());
202 } else {
203 PostErrorResult(callback, RESULT_FAILED_TO_START);
207 void NativeProcessLauncherImpl::Core::CallCallbackOnIOThread(
208 LaunchedCallback callback,
209 LaunchResult result,
210 base::ProcessHandle process_handle,
211 base::File read_file,
212 base::File write_file) {
213 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
214 if (detached_)
215 return;
217 callback.Run(result, process_handle, read_file.Pass(), write_file.Pass());
220 void NativeProcessLauncherImpl::Core::PostErrorResult(
221 const LaunchedCallback& callback,
222 LaunchResult error) {
223 content::BrowserThread::PostTask(
224 content::BrowserThread::IO, FROM_HERE,
225 base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
226 callback, error, base::kNullProcessHandle,
227 Passed(base::File()), Passed(base::File())));
230 void NativeProcessLauncherImpl::Core::PostResult(
231 const LaunchedCallback& callback,
232 base::ProcessHandle process_handle,
233 base::File read_file,
234 base::File write_file) {
235 content::BrowserThread::PostTask(
236 content::BrowserThread::IO, FROM_HERE,
237 base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
238 callback, RESULT_SUCCESS, process_handle,
239 Passed(read_file.Pass()), Passed(write_file.Pass())));
242 NativeProcessLauncherImpl::NativeProcessLauncherImpl(
243 bool allow_user_level_hosts,
244 intptr_t window_handle)
245 : core_(new Core(allow_user_level_hosts, window_handle)) {
248 NativeProcessLauncherImpl::~NativeProcessLauncherImpl() {
249 core_->Detach();
252 void NativeProcessLauncherImpl::Launch(const GURL& origin,
253 const std::string& native_host_name,
254 LaunchedCallback callback) const {
255 core_->Launch(origin, native_host_name, callback);
258 } // namespace
260 // static
261 scoped_ptr<NativeProcessLauncher> NativeProcessLauncher::CreateDefault(
262 bool allow_user_level_hosts,
263 gfx::NativeView native_view) {
264 intptr_t window_handle = 0;
265 #if defined(OS_WIN)
266 window_handle = reinterpret_cast<intptr_t>(
267 views::HWNDForNativeView(native_view));
268 #endif
269 return scoped_ptr<NativeProcessLauncher>(
270 new NativeProcessLauncherImpl(allow_user_level_hosts, window_handle));
273 } // namespace extensions