Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / messaging / native_process_launcher.cc
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.
4
5 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
6
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 "chrome/common/chrome_switches.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "url/gurl.h"
23
24 #if defined(OS_WIN)
25 #include "ui/views/win/hwnd_util.h"
26 #endif
27
28 namespace extensions {
29
30 namespace {
31
32 #if defined(OS_WIN)
33 // Name of the command line switch used to pass handle of the native view to
34 // the native messaging host.
35 const char kParentWindowSwitchName[] = "parent-window";
36 #endif  // defined(OS_WIN)
37
38 // Default implementation on NativeProcessLauncher interface.
39 class NativeProcessLauncherImpl : public NativeProcessLauncher {
40  public:
41   NativeProcessLauncherImpl(bool allow_user_level_hosts,
42                             intptr_t native_window);
43   virtual ~NativeProcessLauncherImpl();
44
45   virtual void Launch(const GURL& origin,
46                       const std::string& native_host_name,
47                       LaunchedCallback callback) const OVERRIDE;
48
49  private:
50   class Core : public base::RefCountedThreadSafe<Core> {
51    public:
52     Core(bool allow_user_level_hosts, intptr_t native_window);
53     void Launch(const GURL& origin,
54                 const std::string& native_host_name,
55                 LaunchedCallback callback);
56     void Detach();
57
58    private:
59     friend class base::RefCountedThreadSafe<Core>;
60     virtual ~Core();
61
62     void DoLaunchOnThreadPool(const GURL& origin,
63                               const std::string& native_host_name,
64                               LaunchedCallback callback);
65     void PostErrorResult(const LaunchedCallback& callback, LaunchResult error);
66     void PostResult(const LaunchedCallback& callback,
67                     base::ProcessHandle process_handle,
68                     base::File read_file,
69                     base::File write_file);
70     void CallCallbackOnIOThread(LaunchedCallback callback,
71                                 LaunchResult result,
72                                 base::ProcessHandle process_handle,
73                                 base::File read_file,
74                                 base::File write_file);
75
76     bool detached_;
77
78     bool allow_user_level_hosts_;
79
80     // Handle of the native window corresponding to the extension.
81     intptr_t window_handle_;
82
83     DISALLOW_COPY_AND_ASSIGN(Core);
84   };
85
86   scoped_refptr<Core> core_;
87
88   DISALLOW_COPY_AND_ASSIGN(NativeProcessLauncherImpl);
89 };
90
91 NativeProcessLauncherImpl::Core::Core(bool allow_user_level_hosts,
92                                       intptr_t window_handle)
93     : detached_(false),
94       allow_user_level_hosts_(allow_user_level_hosts),
95       window_handle_(window_handle) {
96 }
97
98 NativeProcessLauncherImpl::Core::~Core() {
99   DCHECK(detached_);
100 }
101
102 void NativeProcessLauncherImpl::Core::Detach() {
103   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
104   detached_ = true;
105 }
106
107 void NativeProcessLauncherImpl::Core::Launch(
108     const GURL& origin,
109     const std::string& native_host_name,
110     LaunchedCallback callback) {
111   content::BrowserThread::PostBlockingPoolTask(
112       FROM_HERE, base::Bind(&Core::DoLaunchOnThreadPool, this,
113                             origin, native_host_name, callback));
114 }
115
116 void NativeProcessLauncherImpl::Core::DoLaunchOnThreadPool(
117     const GURL& origin,
118     const std::string& native_host_name,
119     LaunchedCallback callback) {
120   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
121
122   if (!NativeMessagingHostManifest::IsValidName(native_host_name)) {
123     PostErrorResult(callback, RESULT_INVALID_NAME);
124     return;
125   }
126
127   std::string error_message;
128   base::FilePath manifest_path =
129       FindManifest(native_host_name, allow_user_level_hosts_, &error_message);
130
131   if (manifest_path.empty()) {
132     LOG(ERROR) << "Can't find manifest for native messaging host "
133                << native_host_name;
134     PostErrorResult(callback, RESULT_NOT_FOUND);
135     return;
136   }
137
138   scoped_ptr<NativeMessagingHostManifest> manifest =
139       NativeMessagingHostManifest::Load(manifest_path, &error_message);
140
141   if (!manifest) {
142     LOG(ERROR) << "Failed to load manifest for native messaging host "
143                << native_host_name << ": " << error_message;
144     PostErrorResult(callback, RESULT_NOT_FOUND);
145     return;
146   }
147
148   if (manifest->name() != native_host_name) {
149     LOG(ERROR) << "Failed to load manifest for native messaging host "
150                << native_host_name
151                << ": Invalid name specified in the manifest.";
152     PostErrorResult(callback, RESULT_NOT_FOUND);
153     return;
154   }
155
156   if (!manifest->allowed_origins().MatchesSecurityOrigin(origin)) {
157     // Not an allowed origin.
158     PostErrorResult(callback, RESULT_FORBIDDEN);
159     return;
160   }
161
162   base::FilePath host_path = manifest->path();
163   if (!host_path.IsAbsolute()) {
164     // On Windows host path is allowed to be relative to the location of the
165     // manifest file. On all other platforms the path must be absolute.
166 #if defined(OS_WIN)
167     host_path = manifest_path.DirName().Append(host_path);
168 #else  // defined(OS_WIN)
169     LOG(ERROR) << "Native messaging host path must be absolute for "
170                << native_host_name;
171     PostErrorResult(callback, RESULT_NOT_FOUND);
172     return;
173 #endif  // !defined(OS_WIN)
174   }
175
176   // In case when the manifest file is there, but the host binary doesn't exist
177   // report the NOT_FOUND error.
178   if (!base::PathExists(host_path)) {
179     LOG(ERROR)
180         << "Found manifest, but not the binary for native messaging host "
181         << native_host_name << ". Host path specified in the manifest: "
182         << host_path.AsUTF8Unsafe();
183     PostErrorResult(callback, RESULT_NOT_FOUND);
184     return;
185   }
186
187   CommandLine command_line(host_path);
188   command_line.AppendArg(origin.spec());
189
190   // Pass handle of the native view window to the native messaging host. This
191   // way the host will be able to create properly focused UI windows.
192 #if defined(OS_WIN)
193   command_line.AppendSwitchASCII(kParentWindowSwitchName,
194                                  base::Int64ToString(window_handle_));
195 #endif  // !defined(OS_WIN)
196
197   base::ProcessHandle process_handle;
198   base::File read_file;
199   base::File write_file;
200   if (NativeProcessLauncher::LaunchNativeProcess(
201           command_line, &process_handle, &read_file, &write_file)) {
202     PostResult(callback, process_handle, read_file.Pass(), write_file.Pass());
203   } else {
204     PostErrorResult(callback, RESULT_FAILED_TO_START);
205   }
206 }
207
208 void NativeProcessLauncherImpl::Core::CallCallbackOnIOThread(
209     LaunchedCallback callback,
210     LaunchResult result,
211     base::ProcessHandle process_handle,
212     base::File read_file,
213     base::File write_file) {
214   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
215   if (detached_)
216     return;
217
218   callback.Run(result, process_handle, read_file.Pass(), write_file.Pass());
219 }
220
221 void NativeProcessLauncherImpl::Core::PostErrorResult(
222     const LaunchedCallback& callback,
223     LaunchResult error) {
224   content::BrowserThread::PostTask(
225       content::BrowserThread::IO, FROM_HERE,
226       base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
227                  callback, error, base::kNullProcessHandle,
228                  Passed(base::File()), Passed(base::File())));
229 }
230
231 void NativeProcessLauncherImpl::Core::PostResult(
232     const LaunchedCallback& callback,
233     base::ProcessHandle process_handle,
234     base::File read_file,
235     base::File write_file) {
236   content::BrowserThread::PostTask(
237       content::BrowserThread::IO, FROM_HERE,
238       base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
239                  callback, RESULT_SUCCESS, process_handle,
240                  Passed(read_file.Pass()), Passed(write_file.Pass())));
241 }
242
243 NativeProcessLauncherImpl::NativeProcessLauncherImpl(
244     bool allow_user_level_hosts,
245     intptr_t window_handle)
246     : core_(new Core(allow_user_level_hosts, window_handle)) {
247 }
248
249 NativeProcessLauncherImpl::~NativeProcessLauncherImpl() {
250   core_->Detach();
251 }
252
253 void NativeProcessLauncherImpl::Launch(const GURL& origin,
254                                        const std::string& native_host_name,
255                                        LaunchedCallback callback) const {
256   core_->Launch(origin, native_host_name, callback);
257 }
258
259 }  // namespace
260
261 // static
262 scoped_ptr<NativeProcessLauncher> NativeProcessLauncher::CreateDefault(
263     bool allow_user_level_hosts,
264     gfx::NativeView native_view) {
265   intptr_t window_handle = 0;
266 #if defined(OS_WIN)
267   window_handle = reinterpret_cast<intptr_t>(
268       views::HWNDForNativeView(native_view));
269 #endif
270   return scoped_ptr<NativeProcessLauncher>(
271       new NativeProcessLauncherImpl(allow_user_level_hosts, window_handle));
272 }
273
274 }  // namespace extensions