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