Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(371)

Side by Side Diff: mojo/shell/dynamic_application_loader.cc

Issue 513573002: Mojo: Fix two bugs in content handling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: darin comments Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/shell/dynamic_application_loader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/shell/dynamic_application_loader.h" 5 #include "mojo/shell/dynamic_application_loader.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
13 #include "mojo/common/common_type_converters.h" 14 #include "mojo/common/common_type_converters.h"
14 #include "mojo/common/data_pipe_utils.h" 15 #include "mojo/common/data_pipe_utils.h"
15 #include "mojo/services/public/interfaces/network/url_loader.mojom.h" 16 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
16 #include "mojo/shell/context.h" 17 #include "mojo/shell/context.h"
17 #include "mojo/shell/switches.h" 18 #include "mojo/shell/switches.h"
18 #include "net/base/filename_util.h" 19 #include "net/base/filename_util.h"
19 20
20 namespace mojo { 21 namespace mojo {
21 namespace shell { 22 namespace shell {
22 23
24 // Encapsulates loading and running one individual application.
25 //
26 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
27 // ensure that all the parameters passed to Loader subclasses stay valid through
28 // Loader's lifetime.
29 //
30 // Async operations are done with WeakPtr to protect against
31 // DynamicApplicationLoader going away (and taking all the Loaders with it)
32 // while the async operation is outstanding.
33 class DynamicApplicationLoader::Loader {
34 public:
35 Loader(Context* context,
36 DynamicServiceRunnerFactory* runner_factory,
37 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
38 const LoaderCompleteCallback& loader_complete_callback)
39 : load_callbacks_(load_callbacks),
40 loader_complete_callback_(loader_complete_callback),
41 context_(context),
42 runner_factory_(runner_factory),
43 weak_ptr_factory_(this) {}
44
45 virtual ~Loader() {}
46
47 protected:
48 void RunLibrary(const base::FilePath& path, bool path_exists) {
49 ScopedMessagePipeHandle shell_handle =
50 load_callbacks_->RegisterApplication();
51 if (!shell_handle.is_valid()) {
52 AppCompleted();
53 return;
54 }
55
56 if (!path_exists) {
57 DVLOG(1) << "Library not started because library path '" << path.value()
58 << "' does not exist.";
59 AppCompleted();
60 return;
61 }
62
63 runner_ = runner_factory_->Create(context_);
64 runner_->Start(
65 path,
66 shell_handle.Pass(),
67 base::Bind(&Loader::AppCompleted, weak_ptr_factory_.GetWeakPtr()));
tim (not reviewing) 2014/08/28 19:11:14 nit: I kind of liked the RunLibrary / OnRunLibrary
Aaron Boodman 2014/08/28 19:49:22 Yeah, but it is run in other situations than when
68 }
69
70 void AppCompleted() { loader_complete_callback_.Run(this); }
71
72 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
73 LoaderCompleteCallback loader_complete_callback_;
74 Context* context_;
75
76 private:
77 DynamicServiceRunnerFactory* runner_factory_;
78 scoped_ptr<DynamicServiceRunner> runner_;
79 base::WeakPtrFactory<Loader> weak_ptr_factory_;
80 };
81
82 // A loader for local files.
83 class DynamicApplicationLoader::LocalLoader : public Loader {
84 public:
85 LocalLoader(const GURL& url,
86 Context* context,
87 DynamicServiceRunnerFactory* runner_factory,
88 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
89 const LoaderCompleteCallback& loader_complete_callback)
90 : Loader(context,
91 runner_factory,
92 load_callbacks,
93 loader_complete_callback),
94 weak_ptr_factory_(this) {
95 base::FilePath path;
96 net::FileURLToFilePath(url, &path);
97
98 // Async for consistency with network case.
99 base::MessageLoop::current()->PostTask(
100 FROM_HERE,
101 base::Bind(&LocalLoader::RunLibrary,
102 weak_ptr_factory_.GetWeakPtr(),
103 path,
104 base::PathExists(path)));
105 }
106
107 virtual ~LocalLoader() {}
108
109 private:
110 base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
111 };
112
113 // A loader for network files.
114 class DynamicApplicationLoader::NetworkLoader : public Loader {
115 public:
116 NetworkLoader(const GURL& url,
117 MimeTypeToURLMap* mime_type_to_url,
118 Context* context,
119 DynamicServiceRunnerFactory* runner_factory,
120 NetworkService* network_service,
121 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
122 const LoaderCompleteCallback& loader_complete_callback)
123 : Loader(context,
124 runner_factory,
125 load_callbacks,
126 loader_complete_callback),
127 mime_type_to_url_(mime_type_to_url),
128 weak_ptr_factory_(this) {
129 URLRequestPtr request(URLRequest::New());
130 request->url = String::From(url);
131 request->auto_follow_redirects = true;
132
133 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
134 switches::kDisableCache)) {
135 request->bypass_cache = true;
136 }
137
138 network_service->CreateURLLoader(Get(&url_loader_));
139 url_loader_->Start(request.Pass(),
140 base::Bind(&NetworkLoader::OnLoadComplete,
141 weak_ptr_factory_.GetWeakPtr()));
142 }
143
144 virtual ~NetworkLoader() {
145 if (!file_.empty())
146 base::DeleteFile(file_, false);
147 }
148
149 private:
150 void OnLoadComplete(URLResponsePtr response) {
151 if (response->error) {
152 LOG(ERROR) << "Error (" << response->error->code << ": "
153 << response->error->description << ") while fetching "
154 << response->url;
155 AppCompleted();
156 return;
157 }
158
159 MimeTypeToURLMap::iterator iter =
160 mime_type_to_url_->find(response->mime_type);
161 if (iter != mime_type_to_url_->end()) {
162 load_callbacks_->LoadWithContentHandler(
163 iter->second, response.Pass(), url_loader_.Pass());
164 AppCompleted();
165 return;
166 }
167
168 base::CreateTemporaryFile(&file_);
169 common::CopyToFile(
170 response->body.Pass(),
171 file_,
172 context_->task_runners()->blocking_pool(),
173 base::Bind(
174 &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_));
175 }
176
177 MimeTypeToURLMap* mime_type_to_url_;
178 URLLoaderPtr url_loader_;
179 base::FilePath file_;
180 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
181 };
182
23 DynamicApplicationLoader::DynamicApplicationLoader( 183 DynamicApplicationLoader::DynamicApplicationLoader(
24 Context* context, 184 Context* context,
25 scoped_ptr<DynamicServiceRunnerFactory> runner_factory) 185 scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
26 : context_(context), 186 : context_(context),
27 runner_factory_(runner_factory.Pass()), 187 runner_factory_(runner_factory.Pass()),
28 weak_ptr_factory_(this) { 188
189 // Unretained() is correct here because DynamicApplicationLoader owns the
190 // loaders that we pass this callback to.
191 loader_complete_callback_(
192 base::Bind(&DynamicApplicationLoader::LoaderComplete,
193 base::Unretained(this))) {
29 } 194 }
30 195
31 DynamicApplicationLoader::~DynamicApplicationLoader() { 196 DynamicApplicationLoader::~DynamicApplicationLoader() {
32 } 197 }
33 198
34 void DynamicApplicationLoader::RegisterContentHandler( 199 void DynamicApplicationLoader::RegisterContentHandler(
35 const std::string& mime_type, 200 const std::string& mime_type,
36 const GURL& content_handler_url) { 201 const GURL& content_handler_url) {
37 mime_type_to_url_[mime_type] = content_handler_url; 202 mime_type_to_url_[mime_type] = content_handler_url;
38 } 203 }
39 204
40 void DynamicApplicationLoader::Load(ApplicationManager* manager, 205 void DynamicApplicationLoader::Load(
41 const GURL& url, 206 ApplicationManager* manager,
42 scoped_refptr<LoadCallbacks> callbacks) { 207 const GURL& url,
208 scoped_refptr<LoadCallbacks> load_callbacks) {
43 GURL resolved_url; 209 GURL resolved_url;
44 if (url.SchemeIs("mojo")) { 210 if (url.SchemeIs("mojo")) {
45 resolved_url = context_->mojo_url_resolver()->Resolve(url); 211 resolved_url = context_->mojo_url_resolver()->Resolve(url);
46 } else { 212 } else {
47 resolved_url = url; 213 resolved_url = url;
48 } 214 }
49 215
50 if (resolved_url.SchemeIsFile()) 216 if (resolved_url.SchemeIsFile()) {
51 LoadLocalService(resolved_url, callbacks); 217 loaders_.push_back(new LocalLoader(resolved_url,
52 else 218 context_,
53 LoadNetworkService(resolved_url, callbacks); 219 runner_factory_.get(),
54 } 220 load_callbacks,
221 loader_complete_callback_));
222 return;
223 }
55 224
56 void DynamicApplicationLoader::LoadLocalService(
57 const GURL& resolved_url,
58 scoped_refptr<LoadCallbacks> callbacks) {
59 base::FilePath path;
60 net::FileURLToFilePath(resolved_url, &path);
61 const bool kDeleteFileAfter = false;
62
63 // Async for consistency with network case.
64 base::MessageLoop::current()->PostTask(
65 FROM_HERE,
66 base::Bind(&DynamicApplicationLoader::RunLibrary,
67 weak_ptr_factory_.GetWeakPtr(),
68 path,
69 callbacks,
70 kDeleteFileAfter,
71 base::PathExists(path)));
72 }
73
74 void DynamicApplicationLoader::LoadNetworkService(
75 const GURL& resolved_url,
76 scoped_refptr<LoadCallbacks> callbacks) {
77 if (!network_service_) { 225 if (!network_service_) {
78 context_->application_manager()->ConnectToService( 226 context_->application_manager()->ConnectToService(
79 GURL("mojo:mojo_network_service"), &network_service_); 227 GURL("mojo:mojo_network_service"), &network_service_);
80 } 228 }
81 if (!url_loader_)
82 network_service_->CreateURLLoader(Get(&url_loader_));
83 229
84 URLRequestPtr request(URLRequest::New()); 230 loaders_.push_back(new NetworkLoader(resolved_url,
85 request->url = String::From(resolved_url); 231 &mime_type_to_url_,
86 request->auto_follow_redirects = true; 232 context_,
87 233 runner_factory_.get(),
88 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 234 network_service_.get(),
89 switches::kDisableCache)) { 235 load_callbacks,
90 request->bypass_cache = true; 236 loader_complete_callback_));
91 }
92
93 url_loader_->Start(
94 request.Pass(),
95 base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete,
96 weak_ptr_factory_.GetWeakPtr(),
97 callbacks));
98 }
99
100 void DynamicApplicationLoader::OnLoadNetworkServiceComplete(
101 scoped_refptr<LoadCallbacks> callbacks,
102 URLResponsePtr response) {
103 if (response->error) {
104 LOG(ERROR) << "Error (" << response->error->code << ": "
105 << response->error->description << ") while fetching "
106 << response->url;
107 }
108
109 MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(response->mime_type);
110 if (iter != mime_type_to_url_.end()) {
111 callbacks->LoadWithContentHandler(iter->second, response.Pass());
112 return;
113 }
114
115 base::FilePath file;
116 base::CreateTemporaryFile(&file);
117
118 const bool kDeleteFileAfter = true;
119 common::CopyToFile(response->body.Pass(),
120 file,
121 context_->task_runners()->blocking_pool(),
122 base::Bind(&DynamicApplicationLoader::RunLibrary,
123 weak_ptr_factory_.GetWeakPtr(),
124 file,
125 callbacks,
126 kDeleteFileAfter));
127 }
128
129 void DynamicApplicationLoader::RunLibrary(
130 const base::FilePath& path,
131 scoped_refptr<LoadCallbacks> callbacks,
132 bool delete_file_after,
133 bool path_exists) {
134
135 ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
136 if (!shell_handle.is_valid())
137 return;
138
139 if (!path_exists) {
140 DVLOG(1) << "Library not started because library path '"
141 << path.value() << "' does not exist.";
142 return;
143 }
144
145 scoped_ptr<DynamicServiceRunner> runner =
146 runner_factory_->Create(context_).Pass();
147 runner->Start(path,
148 shell_handle.Pass(),
149 base::Bind(&DynamicApplicationLoader::OnRunLibraryComplete,
150 weak_ptr_factory_.GetWeakPtr(),
151 base::Unretained(runner.get()),
152 delete_file_after ? path : base::FilePath()));
153 runners_.push_back(runner.release());
154 }
155
156 void DynamicApplicationLoader::OnRunLibraryComplete(
157 DynamicServiceRunner* runner,
158 const base::FilePath& temp_file) {
159 for (ScopedVector<DynamicServiceRunner>::iterator it = runners_.begin();
160 it != runners_.end(); ++it) {
161 if (*it == runner) {
162 runners_.erase(it);
163 if (!temp_file.empty())
164 base::DeleteFile(temp_file, false);
165 return;
166 }
167 }
168 } 237 }
169 238
170 void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager, 239 void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager,
171 const GURL& url) { 240 const GURL& url) {
172 // TODO(darin): What should we do about service errors? This implies that 241 // TODO(darin): What should we do about service errors? This implies that
173 // the app closed its handle to the service manager. Maybe we don't care? 242 // the app closed its handle to the service manager. Maybe we don't care?
174 } 243 }
175 244
245 void DynamicApplicationLoader::LoaderComplete(Loader* loader) {
246 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader));
247 }
248
176 } // namespace shell 249 } // namespace shell
177 } // namespace mojo 250 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/dynamic_application_loader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698