Upstream version 11.39.256.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/application/browser/application.h"
6
7 #include <string>
8
9 #include "base/files/file_enumerator.h"
10 #include "base/json/json_reader.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "base/values.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/site_instance.h"
20 #include "net/base/net_util.h"
21 #include "xwalk/application/common/application_manifest_constants.h"
22 #include "xwalk/application/common/constants.h"
23 #include "xwalk/application/common/manifest_handlers/warp_handler.h"
24 #include "xwalk/runtime/browser/runtime.h"
25 #include "xwalk/runtime/browser/runtime_ui_delegate.h"
26 #include "xwalk/runtime/browser/xwalk_browser_context.h"
27 #include "xwalk/runtime/browser/xwalk_runner.h"
28
29 #if defined(OS_TIZEN)
30 #include "xwalk/application/browser/application_tizen.h"
31 #endif
32
33 using content::RenderProcessHost;
34
35 namespace xwalk {
36
37 namespace keys = application_manifest_keys;
38 namespace widget_keys = application_widget_keys;
39
40 namespace {
41 const char* kDefaultWidgetEntryPage[] = {
42 "index.html",
43 "index.htm",
44 "index.svg",
45 "index.xhtml",
46 "index.xht"};
47
48 GURL GetDefaultWidgetEntryPage(
49     scoped_refptr<xwalk::application::ApplicationData> data) {
50   base::ThreadRestrictions::SetIOAllowed(true);
51   base::FileEnumerator iter(
52       data->path(), true,
53       base::FileEnumerator::FILES,
54       FILE_PATH_LITERAL("index.*"));
55   size_t priority = arraysize(kDefaultWidgetEntryPage);
56   std::string source;
57
58   for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
59     for (size_t i = 0; i < arraysize(kDefaultWidgetEntryPage); ++i) {
60       if (file.BaseName().MaybeAsASCII() == kDefaultWidgetEntryPage[i] &&
61           i < priority) {
62         source = kDefaultWidgetEntryPage[i];
63         priority = i;
64       }
65     }
66   }
67
68   return source.empty() ? GURL() : data->GetResourceURL(source);
69 }
70
71 }  // namespace
72
73 namespace application {
74
75 scoped_ptr<Application> Application::Create(
76     scoped_refptr<ApplicationData> data,
77     XWalkBrowserContext* context) {
78 #if defined(OS_TIZEN)
79   return make_scoped_ptr<Application>(new ApplicationTizen(data, context));
80 #else
81   return make_scoped_ptr(new Application(data, context));
82 #endif
83 }
84
85 Application::Application(
86     scoped_refptr<ApplicationData> data,
87     XWalkBrowserContext* browser_context)
88     : data_(data),
89       render_process_host_(NULL),
90       web_contents_(NULL),
91       security_mode_enabled_(false),
92       browser_context_(browser_context),
93       observer_(NULL),
94       remote_debugging_enabled_(false),
95       weak_factory_(this) {
96   DCHECK(browser_context_);
97   DCHECK(data_.get());
98 }
99
100 Application::~Application() {
101   Terminate();
102   if (render_process_host_)
103     render_process_host_->RemoveObserver(this);
104 }
105
106 template<>
107 GURL Application::GetStartURL<Manifest::TYPE_WIDGET>() {
108 #if defined(OS_TIZEN)
109   if (data_->IsHostedApp()) {
110     std::string source;
111     GURL url;
112     if (data_->GetManifest()->GetString(
113         widget_keys::kLaunchLocalPathKey, &source)) {
114       url = GURL(source);
115     }
116
117     if (url.is_valid() && url.SchemeIsHTTPOrHTTPS())
118       return url;
119   }
120 #endif
121
122   GURL url = GetAbsoluteURLFromKey(widget_keys::kLaunchLocalPathKey);
123   if (url.is_valid())
124     return url;
125
126   LOG(WARNING) << "Failed to find start URL from the 'config.xml'"
127                << "trying to find default entry page.";
128   url = GetDefaultWidgetEntryPage(data_);
129   if (url.is_valid())
130     return url;
131
132   LOG(WARNING) << "Failed to find a valid start URL in the manifest.";
133   return GURL();
134 }
135
136 template<>
137 GURL Application::GetStartURL<Manifest::TYPE_MANIFEST>() {
138   if (data_->IsHostedApp()) {
139     std::string source;
140     // Not trying to get a relative path for the "fake" application.
141     if (data_->GetManifest()->GetString(keys::kStartURLKey, &source))
142       return GURL(source);
143     return GURL();
144   }
145
146   GURL url = GetAbsoluteURLFromKey(keys::kStartURLKey);
147   if (url.is_valid())
148     return url;
149
150   url = GetAbsoluteURLFromKey(keys::kLaunchLocalPathKey);
151   if (url.is_valid())
152     return url;
153
154   url = GetAbsoluteURLFromKey(keys::kDeprecatedURLKey);
155   if (url.is_valid()) {
156     LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedURLKey
157         << "' found. Please migrate to using '" << keys::kStartURLKey
158         << "' instead.";
159     return url;
160   }
161
162   LOG(WARNING) << "Failed to find a valid start URL in the manifest.";
163   return GURL();
164 }
165
166
167 template<>
168 ui::WindowShowState Application::GetWindowShowState<Manifest::TYPE_WIDGET>(
169     const LaunchParams& params) {
170   if (params.force_fullscreen)
171     return ui::SHOW_STATE_FULLSCREEN;
172
173   const Manifest* manifest = data_->GetManifest();
174   std::string view_modes_string;
175   if (manifest->GetString(widget_keys::kViewModesKey, &view_modes_string)) {
176     // FIXME: ATM only 'fullscreen' and 'windowed' values are supported.
177     // If the first user prefererence is 'fullscreen', set window show state
178     // FULLSCREEN, otherwise set the default window show state.
179     std::vector<std::string> modes;
180     base::SplitString(view_modes_string, ' ', &modes);
181     if (!modes.empty() && modes[0] == "fullscreen")
182       return ui::SHOW_STATE_FULLSCREEN;
183   }
184
185   return ui::SHOW_STATE_DEFAULT;
186 }
187
188 template<>
189 ui::WindowShowState Application::GetWindowShowState<Manifest::TYPE_MANIFEST>(
190     const LaunchParams& params) {
191   if (params.force_fullscreen)
192     return ui::SHOW_STATE_FULLSCREEN;
193
194   const Manifest* manifest = data_->GetManifest();
195   std::string display_string;
196   if (manifest->GetString(keys::kDisplay, &display_string)) {
197     // FIXME: ATM only 'fullscreen' and 'standalone' (which is fallback value)
198     // values are supported.
199     if (display_string.find("fullscreen") != std::string::npos)
200       return ui::SHOW_STATE_FULLSCREEN;
201   }
202
203   return ui::SHOW_STATE_DEFAULT;
204 }
205
206 bool Application::Launch(const LaunchParams& launch_params) {
207   if (!runtimes_.empty()) {
208     LOG(ERROR) << "Attempt to launch app with id " << id()
209                << ", but it is already running.";
210     return false;
211   }
212
213   CHECK(!render_process_host_);
214   bool is_wgt = data_->manifest_type() == Manifest::TYPE_WIDGET;
215
216   GURL url = is_wgt ? GetStartURL<Manifest::TYPE_WIDGET>() :
217                       GetStartURL<Manifest::TYPE_MANIFEST>();
218   if (!url.is_valid())
219     return false;
220
221   remote_debugging_enabled_ = launch_params.remote_debugging;
222   auto site = content::SiteInstance::CreateForURL(browser_context_, url);
223   Runtime* runtime = Runtime::Create(browser_context_, site);
224   runtime->set_observer(this);
225   runtimes_.push_back(runtime);
226   render_process_host_ = runtime->GetRenderProcessHost();
227   render_process_host_->AddObserver(this);
228   web_contents_ = runtime->web_contents();
229   InitSecurityPolicy();
230   runtime->LoadURL(url);
231
232   NativeAppWindow::CreateParams params;
233   params.net_wm_pid = launch_params.launcher_pid;
234   params.state = is_wgt ?
235       GetWindowShowState<Manifest::TYPE_WIDGET>(launch_params) :
236       GetWindowShowState<Manifest::TYPE_MANIFEST>(launch_params);
237
238   window_show_params_ = params;
239   // Only the first runtime can have a launch screen.
240   params.splash_screen_path = GetSplashScreenPath();
241   runtime->set_ui_delegate(DefaultRuntimeUIDelegate::Create(runtime, params));
242   // We call "Show" after RP is initialized to reduce
243   // the application start up time.
244
245   return true;
246 }
247
248 GURL Application::GetAbsoluteURLFromKey(const std::string& key) {
249   const Manifest* manifest = data_->GetManifest();
250   std::string source;
251
252   if (!manifest->GetString(key, &source) || source.empty())
253     return GURL();
254
255   return data_->GetResourceURL(source);
256 }
257
258 void Application::Terminate() {
259   std::vector<Runtime*> to_be_closed(runtimes_.get());
260   for (Runtime* runtime : to_be_closed)
261     runtime->Close();
262 }
263
264 int Application::GetRenderProcessHostID() const {
265   DCHECK(render_process_host_);
266   return render_process_host_->GetID();
267 }
268
269 void Application::OnNewRuntimeAdded(Runtime* runtime) {
270   runtime->set_remote_debugging_enabled(remote_debugging_enabled_);
271   runtime->set_observer(this);
272   runtime->set_ui_delegate(
273       DefaultRuntimeUIDelegate::Create(runtime, window_show_params_));
274   runtime->Show();
275   runtimes_.push_back(runtime);
276 }
277
278 void Application::OnRuntimeClosed(Runtime* runtime) {
279   auto found = std::find(runtimes_.begin(), runtimes_.end(), runtime);
280   CHECK(found != runtimes_.end());
281   LOG(INFO) << "Application::OnRuntimeClosed " << runtime;
282   runtimes_.erase(found);
283
284   if (runtimes_.empty())
285     base::MessageLoop::current()->PostTask(FROM_HERE,
286         base::Bind(&Application::NotifyTermination,
287                    weak_factory_.GetWeakPtr()));
288 }
289
290 void Application::RenderProcessExited(RenderProcessHost* host,
291                                       base::ProcessHandle,
292                                       base::TerminationStatus,
293                                       int) {
294   DCHECK(render_process_host_ == host);
295   VLOG(1) << "RenderProcess id: " << host->GetID() << " is gone!";
296   XWalkRunner::GetInstance()->OnRenderProcessHostGone(host);
297 }
298
299 void Application::RenderProcessHostDestroyed(RenderProcessHost* host) {
300   DCHECK(render_process_host_ == host);
301   render_process_host_ = NULL;
302   web_contents_ = NULL;
303 }
304
305 void Application::NotifyTermination() {
306   CHECK(!render_process_host_);
307   if (observer_)
308     observer_->OnApplicationTerminated(this);
309 }
310
311 void Application::RenderChannelCreated() {
312   CHECK(!runtimes_.empty());
313   runtimes_.front()->Show();
314 }
315
316 bool Application::UseExtension(const std::string& extension_name) const {
317   // TODO(Bai): Tells whether the application contains the specified extension
318   return true;
319 }
320
321 bool Application::RegisterPermissions(const std::string& extension_name,
322                                       const std::string& perm_table) {
323   // TODO(Bai): Parse the permission table and fill in the name_perm_map_
324   // The perm_table format is a simple JSON string, like
325   // [{"permission_name":"echo","apis":["add","remove","get"]}]
326   scoped_ptr<base::Value> root;
327   root.reset(base::JSONReader().ReadToValue(perm_table));
328   if (root.get() == NULL || !root->IsType(base::Value::TYPE_LIST))
329     return false;
330
331   base::ListValue* permission_list = static_cast<base::ListValue*>(root.get());
332   if (permission_list->GetSize() == 0)
333     return false;
334
335   for (base::ListValue::const_iterator iter = permission_list->begin();
336       iter != permission_list->end(); ++iter) {
337     if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY))
338         return false;
339
340     base::DictionaryValue* dict_val =
341         static_cast<base::DictionaryValue*>(*iter);
342     std::string permission_name;
343     if (!dict_val->GetString("permission_name", &permission_name))
344       return false;
345
346     base::ListValue* api_list = NULL;
347     if (!dict_val->GetList("apis", &api_list))
348       return false;
349
350     for (base::ListValue::const_iterator api_iter = api_list->begin();
351         api_iter != api_list->end(); ++api_iter) {
352       std::string api;
353       if (!((*api_iter)->IsType(base::Value::TYPE_STRING)
354           && (*api_iter)->GetAsString(&api)))
355         return false;
356       // register the permission and api
357       name_perm_map_[api] = permission_name;
358       DLOG(INFO) << "Permission Registered [PERM] " << permission_name
359                  << " [API] " << api;
360     }
361   }
362
363   return true;
364 }
365
366 std::string Application::GetRegisteredPermissionName(
367     const std::string& extension_name,
368     const std::string& api_name) const {
369   std::map<std::string, std::string>::const_iterator iter =
370       name_perm_map_.find(api_name);
371   if (iter == name_perm_map_.end())
372     return std::string("");
373   return iter->second;
374 }
375
376 StoredPermission Application::GetPermission(PermissionType type,
377                                const std::string& permission_name) const {
378   if (type == SESSION_PERMISSION) {
379     StoredPermissionMap::const_iterator iter =
380         permission_map_.find(permission_name);
381     if (iter == permission_map_.end())
382       return UNDEFINED_STORED_PERM;
383     return iter->second;
384   }
385   if (type == PERSISTENT_PERMISSION) {
386     return data_->GetPermission(permission_name);
387   }
388   NOTREACHED();
389   return UNDEFINED_STORED_PERM;
390 }
391
392 bool Application::SetPermission(PermissionType type,
393                                 const std::string& permission_name,
394                                 StoredPermission perm) {
395   if (type == SESSION_PERMISSION) {
396     permission_map_[permission_name] = perm;
397     return true;
398   }
399   if (type == PERSISTENT_PERMISSION)
400     return data_->SetPermission(permission_name, perm);
401
402   NOTREACHED();
403   return false;
404 }
405
406 void Application::InitSecurityPolicy() {
407   // CSP policy takes precedence over WARP.
408   if (data_->HasCSPDefined())
409     security_policy_.reset(new ApplicationSecurityPolicyCSP(this));
410   else if (data_->manifest_type() == Manifest::TYPE_WIDGET)
411     security_policy_.reset(new ApplicationSecurityPolicyWARP(this));
412
413   if (security_policy_)
414     security_policy_->Enforce();
415 }
416
417 bool Application::CanRequestURL(const GURL& url) const {
418   if (security_policy_)
419     return security_policy_->IsAccessAllowed(url);
420   return true;
421 }
422
423 base::FilePath Application::GetSplashScreenPath() {
424   return base::FilePath();
425 }
426
427 }  // namespace application
428 }  // namespace xwalk