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

Side by Side Diff: mojo/shell/package_manager/package_manager_impl.cc

Issue 1701933004: Remove the old package manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@am2
Patch Set: . Created 4 years, 10 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/package_manager/package_manager_impl.h ('k') | mojo/shell/query_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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/package_manager/package_manager_impl.h"
6
7 #include <stdint.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/json/json_file_value_serializer.h"
13 #include "base/logging.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/task_runner_util.h"
16 #include "base/values.h"
17 #include "mojo/shell/application_manager.h"
18 #include "mojo/shell/connect_util.h"
19 #include "mojo/shell/fetcher/about_fetcher.h"
20 #include "mojo/shell/fetcher/data_fetcher.h"
21 #include "mojo/shell/fetcher/local_fetcher.h"
22 #include "mojo/shell/fetcher/network_fetcher.h"
23 #include "mojo/shell/fetcher/switches.h"
24 #include "mojo/shell/package_manager/content_handler_connection.h"
25 #include "mojo/shell/public/interfaces/content_handler.mojom.h"
26 #include "mojo/shell/query_util.h"
27 #include "mojo/shell/switches.h"
28 #include "mojo/util/filename_util.h"
29 #include "net/base/filename_util.h"
30 #include "url/gurl.h"
31
32 namespace mojo {
33 namespace shell {
34 namespace {
35
36 CapabilityFilter BuildCapabilityFilterFromDictionary(
37 const base::DictionaryValue& value) {
38 CapabilityFilter filter;
39 base::DictionaryValue::Iterator it(value);
40 for (; !it.IsAtEnd(); it.Advance()) {
41 const base::ListValue* values = nullptr;
42 CHECK(it.value().GetAsList(&values));
43 AllowedInterfaces interfaces;
44 for (auto i = values->begin(); i != values->end(); ++i) {
45 std::string iface_name;
46 const base::Value* v = *i;
47 CHECK(v->GetAsString(&iface_name));
48 interfaces.insert(iface_name);
49 }
50 filter[it.key()] = interfaces;
51 }
52 return filter;
53 }
54
55 ApplicationInfo BuildApplicationInfoFromDictionary(
56 const base::DictionaryValue& value) {
57 ApplicationInfo info;
58 CHECK(value.GetString("url", &info.url));
59 CHECK(value.GetString("name", &info.name));
60 const base::DictionaryValue* capabilities = nullptr;
61 CHECK(value.GetDictionary("capabilities", &capabilities));
62 info.base_filter = BuildCapabilityFilterFromDictionary(*capabilities);
63 return info;
64 }
65
66 void SerializeEntry(const ApplicationInfo& entry,
67 base::DictionaryValue** value) {
68 *value = new base::DictionaryValue;
69 (*value)->SetString("url", entry.url);
70 (*value)->SetString("name", entry.name);
71 base::DictionaryValue* capabilities = new base::DictionaryValue;
72 for (const auto& pair : entry.base_filter) {
73 scoped_ptr<base::ListValue> interfaces(new base::ListValue);
74 for (const auto& iface_name : pair.second)
75 interfaces->AppendString(iface_name);
76 capabilities->Set(pair.first, std::move(interfaces));
77 }
78 (*value)->Set("capabilities", make_scoped_ptr(capabilities));
79 }
80
81 }
82
83 ApplicationInfo::ApplicationInfo() {}
84 ApplicationInfo::~ApplicationInfo() {}
85
86 ApplicationCatalogStore::~ApplicationCatalogStore() {}
87
88 PackageManagerImpl::PackageManagerImpl(
89 const base::FilePath& shell_file_root,
90 base::TaskRunner* task_runner,
91 ApplicationCatalogStore* catalog_store)
92 : application_manager_(nullptr),
93 disable_cache_(base::CommandLine::ForCurrentProcess()->HasSwitch(
94 switches::kDisableCache)),
95 content_handler_id_counter_(0u),
96 task_runner_(task_runner),
97 shell_file_root_(shell_file_root),
98 catalog_store_(catalog_store) {
99 if (!shell_file_root.empty()) {
100 GURL mojo_root_file_url =
101 util::FilePathToFileURL(shell_file_root).Resolve(std::string());
102 url_resolver_.reset(new URLResolver(mojo_root_file_url));
103 }
104 DeserializeCatalog();
105 }
106
107 PackageManagerImpl::~PackageManagerImpl() {
108 IdentityToContentHandlerMap identity_to_content_handler(
109 identity_to_content_handler_);
110 for (auto& pair : identity_to_content_handler)
111 pair.second->CloseConnection();
112 }
113
114 void PackageManagerImpl::RegisterContentHandler(
115 const std::string& mime_type,
116 const GURL& content_handler_url) {
117 DCHECK(content_handler_url.is_valid())
118 << "Content handler URL is invalid for mime type " << mime_type;
119 mime_type_to_url_[mime_type] = content_handler_url;
120 }
121
122 void PackageManagerImpl::RegisterApplicationPackageAlias(
123 const GURL& alias,
124 const GURL& content_handler_package,
125 const std::string& qualifier) {
126 application_package_alias_[alias] =
127 std::make_pair(content_handler_package, qualifier);
128 }
129
130 void PackageManagerImpl::SetApplicationManager(ApplicationManager* manager) {
131 application_manager_ = manager;
132 }
133
134 void PackageManagerImpl::BuiltinAppLoaded(const GURL& url) {
135 // TODO(beng): Determine if this is in the right place, and block
136 // establishing the connection on receiving a complete manifest.
137 EnsureURLInCatalog(url);
138 }
139
140 void PackageManagerImpl::FetchRequest(
141 URLRequestPtr request,
142 const Fetcher::FetchCallback& loader_callback) {
143 GURL url(request->url.get());
144 if (url.SchemeIs(AboutFetcher::kAboutScheme)) {
145 AboutFetcher::Start(url, loader_callback);
146 return;
147 }
148
149 if (url.SchemeIs(url::kDataScheme)) {
150 DataFetcher::Start(url, loader_callback);
151 return;
152 }
153
154 GURL resolved_url = ResolveURL(url);
155 if (resolved_url.SchemeIsFile()) {
156 // LocalFetcher uses the network service to infer MIME types from URLs.
157 // Skip this for mojo URLs to avoid recursively loading the network service.
158 if (!network_service_ && !url.SchemeIs("mojo") && !url.SchemeIs("exe")) {
159 ConnectToInterface(application_manager_, GURL("mojo:network_service"),
160 &network_service_);
161 }
162 // Ownership of this object is transferred to |loader_callback|.
163 // TODO(beng): this is eff'n weird.
164 new LocalFetcher(network_service_.get(), resolved_url,
165 GetBaseURLAndQuery(resolved_url, nullptr),
166 shell_file_root_, loader_callback);
167
168 // TODO(beng): Determine if this is in the right place, and block
169 // establishing the connection on receiving a complete manifest.
170 EnsureURLInCatalog(url);
171 return;
172 }
173
174 if (!url_loader_factory_) {
175 ConnectToInterface(application_manager_, GURL("mojo:network_service"),
176 &url_loader_factory_);
177 }
178
179 // Ownership of this object is transferred to |loader_callback|.
180 // TODO(beng): this is eff'n weird.
181 new NetworkFetcher(disable_cache_, std::move(request),
182 url_loader_factory_.get(), loader_callback);
183 }
184
185 uint32_t PackageManagerImpl::HandleWithContentHandler(
186 Fetcher* fetcher,
187 const Identity& source,
188 const GURL& target_url,
189 const CapabilityFilter& target_filter,
190 InterfaceRequest<mojom::ShellClient>* request) {
191 Identity content_handler_identity;
192 URLResponsePtr response;
193 if (ShouldHandleWithContentHandler(fetcher,
194 target_url,
195 target_filter,
196 &content_handler_identity,
197 &response)) {
198 ContentHandlerConnection* connection =
199 GetContentHandler(content_handler_identity, source);
200 connection->StartApplication(std::move(*request), std::move(response));
201 return connection->id();
202 }
203 return mojom::Shell::kInvalidApplicationID;
204 }
205
206 bool PackageManagerImpl::IsURLInCatalog(const std::string& url) const {
207 return catalog_.find(url) != catalog_.end();
208 }
209
210 std::string PackageManagerImpl::GetApplicationName(
211 const std::string& url) const {
212 auto it = catalog_.find(url);
213 return it != catalog_.end() ? it->second.name : url;
214 }
215
216 GURL PackageManagerImpl::ResolveMojoURL(const GURL& mojo_url) {
217 return ResolveURL(mojo_url);
218 }
219
220 uint32_t PackageManagerImpl::StartContentHandler(
221 const Identity& source,
222 const Identity& content_handler,
223 const GURL& url,
224 mojom::ShellClientRequest request) {
225 URLResponsePtr response(URLResponse::New());
226 response->url = url.spec();
227 ContentHandlerConnection* connection =
228 GetContentHandler(content_handler, source);
229 connection->StartApplication(std::move(request), std::move(response));
230 return connection->id();
231 }
232
233 GURL PackageManagerImpl::ResolveURL(const GURL& url) {
234 return url_resolver_.get() ? url_resolver_->ResolveMojoURL(url) : url;
235 }
236
237 bool PackageManagerImpl::ShouldHandleWithContentHandler(
238 Fetcher* fetcher,
239 const GURL& target_url,
240 const CapabilityFilter& target_filter,
241 Identity* content_handler_identity,
242 URLResponsePtr* response) const {
243 // TODO(beng): it seems like some delegate should/would want to have a say in
244 // configuring the qualifier also.
245 // Why can't we use the real qualifier in single process mode? Because of
246 // base::AtExitManager. If you link in ApplicationRunner into your code, and
247 // then we make initialize multiple copies of the application, we end up
248 // with multiple AtExitManagers and will check on the second one being
249 // created.
250 //
251 // Why doesn't that happen when running different apps? Because
252 // your_thing.mojo!base::AtExitManager and
253 // my_thing.mojo!base::AtExitManager are different symbols.
254 bool use_real_qualifier = !base::CommandLine::ForCurrentProcess()->HasSwitch(
255 switches::kSingleProcess);
256
257 GURL content_handler_url;
258 // The response begins with a #!mojo <content-handler-url>.
259 std::string shebang;
260 if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) {
261 *response = fetcher->AsURLResponse(task_runner_,
262 static_cast<int>(shebang.size()));
263 *content_handler_identity = Identity(
264 content_handler_url,
265 use_real_qualifier ? (*response)->site.To<std::string>()
266 : std::string(),
267 target_filter);
268 return true;
269 }
270
271 // The response MIME type matches a registered content handler.
272 auto iter = mime_type_to_url_.find(fetcher->MimeType());
273 if (iter != mime_type_to_url_.end()) {
274 *response = fetcher->AsURLResponse(task_runner_, 0);
275 *content_handler_identity = Identity(
276 iter->second,
277 use_real_qualifier ? (*response)->site.To<std::string>()
278 : std::string(),
279 target_filter);
280 return true;
281 }
282
283 // The response URL matches a registered content handler.
284 auto alias_iter = application_package_alias_.find(target_url);
285 if (alias_iter != application_package_alias_.end()) {
286 // We replace the qualifier with the one our package alias requested.
287 *response = URLResponse::New();
288 (*response)->url = target_url.spec();
289 *content_handler_identity = Identity(
290 alias_iter->second.first,
291 use_real_qualifier ? alias_iter->second.second : std::string(),
292 target_filter);
293 return true;
294 }
295
296 return false;
297 }
298
299 ContentHandlerConnection* PackageManagerImpl::GetContentHandler(
300 const Identity& content_handler_identity,
301 const Identity& source_identity) {
302 auto it = identity_to_content_handler_.find(content_handler_identity);
303 if (it != identity_to_content_handler_.end())
304 return it->second;
305
306 ContentHandlerConnection* connection = new ContentHandlerConnection(
307 application_manager_, source_identity,
308 content_handler_identity,
309 ++content_handler_id_counter_,
310 base::Bind(&PackageManagerImpl::OnContentHandlerConnectionClosed,
311 base::Unretained(this)));
312 identity_to_content_handler_[content_handler_identity] = connection;
313 return connection;
314 }
315
316 void PackageManagerImpl::OnContentHandlerConnectionClosed(
317 ContentHandlerConnection* connection) {
318 // Remove the mapping.
319 auto it = identity_to_content_handler_.find(connection->identity());
320 DCHECK(it != identity_to_content_handler_.end());
321 identity_to_content_handler_.erase(it);
322 }
323
324 void PackageManagerImpl::EnsureURLInCatalog(const GURL& url) {
325 if (IsURLInCatalog(url.spec()) || !url_resolver_)
326 return;
327
328 GURL manifest_url = url_resolver_->ResolveMojoManifest(url);
329 if (manifest_url.is_empty())
330 return;
331 base::FilePath manifest_path;
332 CHECK(net::FileURLToFilePath(manifest_url, &manifest_path));
333 base::PostTaskAndReplyWithResult(
334 task_runner_, FROM_HERE,
335 base::Bind(&PackageManagerImpl::ReadManifest, base::Unretained(this),
336 manifest_path),
337 base::Bind(&PackageManagerImpl::OnReadManifest,
338 base::Unretained(this)));
339 }
340
341 void PackageManagerImpl::DeserializeCatalog() {
342 ApplicationInfo info;
343 info.url = "mojo://shell/";
344 info.name = "Mojo Shell";
345 catalog_[info.url] = info;
346
347 if (!catalog_store_)
348 return;
349 base::ListValue* catalog = nullptr;
350 catalog_store_->GetStore(&catalog);
351 CHECK(catalog);
352 for (auto it = catalog->begin(); it != catalog->end(); ++it) {
353 const base::DictionaryValue* dictionary = nullptr;
354 const base::Value* v = *it;
355 CHECK(v->GetAsDictionary(&dictionary));
356 DeserializeApplication(dictionary);
357 }
358 }
359
360 void PackageManagerImpl::SerializeCatalog() {
361 scoped_ptr<base::ListValue> catalog(new base::ListValue);
362 for (const auto& info : catalog_) {
363 base::DictionaryValue* dictionary = nullptr;
364 SerializeEntry(info.second, &dictionary);
365 catalog->Append(make_scoped_ptr(dictionary));
366 }
367 if (catalog_store_)
368 catalog_store_->UpdateStore(std::move(catalog));
369 }
370
371 const ApplicationInfo& PackageManagerImpl::DeserializeApplication(
372 const base::DictionaryValue* dictionary) {
373 ApplicationInfo info = BuildApplicationInfoFromDictionary(*dictionary);
374 // If another app refers to this app, then we already added an entry for
375 // |info| as a result of reading the first apps manifest.
376 if (catalog_.count(info.url))
377 return catalog_[info.url];
378
379 catalog_[info.url] = info;
380
381 if (dictionary->HasKey("applications")) {
382 const base::ListValue* applications = nullptr;
383 dictionary->GetList("applications", &applications);
384 for (size_t i = 0; i < applications->GetSize(); ++i) {
385 const base::DictionaryValue* child = nullptr;
386 applications->GetDictionary(i, &child);
387 const ApplicationInfo& child_info = DeserializeApplication(child);
388 GURL child_url(child_info.url);
389 RegisterApplicationPackageAlias(child_url, GURL(info.url),
390 child_url.host());
391 }
392 }
393 return catalog_[info.url];
394 }
395
396 scoped_ptr<base::Value> PackageManagerImpl::ReadManifest(
397 const base::FilePath& manifest_path) {
398 JSONFileValueDeserializer deserializer(manifest_path);
399 int error = 0;
400 std::string message;
401 // TODO(beng): probably want to do more detailed error checking. This should
402 // be done when figuring out if to unblock connection completion.
403 return deserializer.Deserialize(&error, &message);
404 }
405
406 void PackageManagerImpl::OnReadManifest(scoped_ptr<base::Value> manifest) {
407 if (!manifest)
408 return;
409
410 base::DictionaryValue* dictionary = nullptr;
411 CHECK(manifest->GetAsDictionary(&dictionary));
412 DeserializeApplication(dictionary);
413 SerializeCatalog();
414 }
415
416 } // namespace shell
417 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/package_manager/package_manager_impl.h ('k') | mojo/shell/query_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698