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.
5 #include "mojo/shell/dynamic_application_loader.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"
26 void RunLibraryComplete(DynamicServiceRunner* runner,
27 const base::FilePath& temp_file) {
29 if (!temp_file.empty())
30 base::DeleteFile(temp_file, false);
35 DynamicApplicationLoader::DynamicApplicationLoader(
37 scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
39 runner_factory_(runner_factory.Pass()),
40 weak_ptr_factory_(this) {
43 DynamicApplicationLoader::~DynamicApplicationLoader() {
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;
52 void DynamicApplicationLoader::Load(ApplicationManager* manager,
54 scoped_refptr<LoadCallbacks> callbacks) {
56 if (url.SchemeIs("mojo")) {
57 resolved_url = context_->mojo_url_resolver()->Resolve(url);
62 if (resolved_url.SchemeIsFile())
63 LoadLocalService(resolved_url, callbacks);
65 LoadNetworkService(resolved_url, callbacks);
68 void DynamicApplicationLoader::LoadLocalService(
69 const GURL& resolved_url,
70 scoped_refptr<LoadCallbacks> callbacks) {
72 net::FileURLToFilePath(resolved_url, &path);
73 const bool kDeleteFileAfter = false;
75 // Async for consistency with network case.
76 base::MessageLoop::current()->PostTask(
78 base::Bind(&DynamicApplicationLoader::RunLibrary,
79 weak_ptr_factory_.GetWeakPtr(),
83 base::PathExists(path)));
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_);
94 network_service_->CreateURLLoader(Get(&url_loader_));
96 URLRequestPtr request(URLRequest::New());
97 request->url = String::From(resolved_url);
98 request->auto_follow_redirects = true;
100 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
101 switches::kDisableCache)) {
102 request->bypass_cache = true;
107 base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete,
108 weak_ptr_factory_.GetWeakPtr(),
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 "
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());
128 base::CreateTemporaryFile(&file);
130 const bool kDeleteFileAfter = true;
131 common::CopyToFile(response->body.Pass(),
133 context_->task_runners()->blocking_pool(),
134 base::Bind(&DynamicApplicationLoader::RunLibrary,
135 weak_ptr_factory_.GetWeakPtr(),
141 void DynamicApplicationLoader::RunLibrary(
142 const base::FilePath& path,
143 scoped_refptr<LoadCallbacks> callbacks,
144 bool delete_file_after,
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
151 scoped_ptr<DynamicServiceRunner> runner(runner_factory_->Create(context_));
155 ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
156 if (!shell_handle.is_valid())
159 DynamicServiceRunner* runner_raw = runner.release();
160 runner_raw->Start(path,
162 base::Bind(&RunLibraryComplete,
163 base::Unretained(runner_raw),
164 delete_file_after ? path : base::FilePath()));
167 void DynamicApplicationLoader::OnServiceError(ApplicationManager* manager,
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?