Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / shell / dynamic_application_loader.cc
1 // Copyright 2014 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 "mojo/shell/dynamic_application_loader.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "mojo/common/common_type_converters.h"
14 #include "mojo/common/data_pipe_utils.h"
15 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
16 #include "mojo/shell/context.h"
17 #include "mojo/shell/keep_alive.h"
18 #include "mojo/shell/switches.h"
19 #include "net/base/filename_util.h"
20
21 namespace mojo {
22 namespace shell {
23
24 namespace {
25
26 void RunLibraryComplete(DynamicServiceRunner* runner,
27                         const base::FilePath& temp_file) {
28   delete runner;
29   if (!temp_file.empty())
30     base::DeleteFile(temp_file, false);
31 }
32
33 }  // namespace
34
35 DynamicApplicationLoader::DynamicApplicationLoader(
36     Context* context,
37     scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
38     : context_(context),
39       runner_factory_(runner_factory.Pass()),
40       weak_ptr_factory_(this) {
41 }
42
43 DynamicApplicationLoader::~DynamicApplicationLoader() {
44 }
45
46 void DynamicApplicationLoader::RegisterContentHandler(
47     const std::string& mime_type,
48     const GURL& content_handler_url) {
49   mime_type_to_url_[mime_type] = content_handler_url;
50 }
51
52 void DynamicApplicationLoader::Load(ApplicationManager* manager,
53                                     const GURL& url,
54                                     scoped_refptr<LoadCallbacks> callbacks) {
55   GURL resolved_url;
56   if (url.SchemeIs("mojo")) {
57     resolved_url = context_->mojo_url_resolver()->Resolve(url);
58   } else {
59     resolved_url = url;
60   }
61
62   if (resolved_url.SchemeIsFile())
63     LoadLocalService(resolved_url, callbacks);
64   else
65     LoadNetworkService(resolved_url, callbacks);
66 }
67
68 void DynamicApplicationLoader::LoadLocalService(
69     const GURL& resolved_url,
70     scoped_refptr<LoadCallbacks> callbacks) {
71   base::FilePath path;
72   net::FileURLToFilePath(resolved_url, &path);
73   const bool kDeleteFileAfter = false;
74
75   // Async for consistency with network case.
76   base::MessageLoop::current()->PostTask(
77       FROM_HERE,
78       base::Bind(&DynamicApplicationLoader::RunLibrary,
79                  weak_ptr_factory_.GetWeakPtr(),
80                  path,
81                  callbacks,
82                  kDeleteFileAfter,
83                  base::PathExists(path)));
84 }
85
86 void DynamicApplicationLoader::LoadNetworkService(
87     const GURL& resolved_url,
88     scoped_refptr<LoadCallbacks> callbacks) {
89   if (!network_service_) {
90     context_->application_manager()->ConnectToService(
91         GURL("mojo:mojo_network_service"), &network_service_);
92   }
93   if (!url_loader_)
94     network_service_->CreateURLLoader(Get(&url_loader_));
95
96   URLRequestPtr request(URLRequest::New());
97   request->url = String::From(resolved_url);
98   request->auto_follow_redirects = true;
99
100   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
101           switches::kDisableCache)) {
102     request->bypass_cache = true;
103   }
104
105   url_loader_->Start(
106       request.Pass(),
107       base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete,
108                  weak_ptr_factory_.GetWeakPtr(),
109                  callbacks));
110 }
111
112 void DynamicApplicationLoader::OnLoadNetworkServiceComplete(
113     scoped_refptr<LoadCallbacks> callbacks,
114     URLResponsePtr response) {
115   if (response->error) {
116     LOG(ERROR) << "Error (" << response->error->code << ": "
117                << response->error->description << ") while fetching "
118                << response->url;
119   }
120
121   MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(response->mime_type);
122   if (iter != mime_type_to_url_.end()) {
123     callbacks->LoadWithContentHandler(iter->second, response.Pass());
124     return;
125   }
126
127   base::FilePath file;
128   base::CreateTemporaryFile(&file);
129
130   const bool kDeleteFileAfter = true;
131   common::CopyToFile(response->body.Pass(),
132                      file,
133                      context_->task_runners()->blocking_pool(),
134                      base::Bind(&DynamicApplicationLoader::RunLibrary,
135                                 weak_ptr_factory_.GetWeakPtr(),
136                                 file,
137                                 callbacks,
138                                 kDeleteFileAfter));
139 }
140
141 void DynamicApplicationLoader::RunLibrary(
142     const base::FilePath& path,
143     scoped_refptr<LoadCallbacks> callbacks,
144     bool delete_file_after,
145     bool path_exists) {
146   // TODO(aa): We need to create a runner, even if we're not going to use it,
147   // because it getting destroyed is what causes shell to shut down. If we don't
148   // create this, in the case where shell never successfully creates even one
149   // app, then shell will never shut down, because no runners are ever
150   // destroyed.
151   scoped_ptr<DynamicServiceRunner> runner(runner_factory_->Create(context_));
152   if (!path_exists)
153     return;
154
155   ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
156   if (!shell_handle.is_valid())
157     return;
158
159   DynamicServiceRunner* runner_raw = runner.release();
160   runner_raw->Start(path,
161                     shell_handle.Pass(),
162                     base::Bind(&RunLibraryComplete,
163                                base::Unretained(runner_raw),
164                                delete_file_after ? path : base::FilePath()));
165 }
166
167 void DynamicApplicationLoader::OnServiceError(ApplicationManager* manager,
168                                               const GURL& url) {
169   // TODO(darin): What should we do about service errors? This implies that
170   // the app closed its handle to the service manager. Maybe we don't care?
171 }
172
173 }  // namespace shell
174 }  // namespace mojo