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/switches.h"
18 #include "net/base/filename_util.h"
23 DynamicApplicationLoader::DynamicApplicationLoader(
25 scoped_ptr
<DynamicServiceRunnerFactory
> runner_factory
)
27 runner_factory_(runner_factory
.Pass()),
28 weak_ptr_factory_(this) {
31 DynamicApplicationLoader::~DynamicApplicationLoader() {
34 void DynamicApplicationLoader::RegisterContentHandler(
35 const std::string
& mime_type
,
36 const GURL
& content_handler_url
) {
37 mime_type_to_url_
[mime_type
] = content_handler_url
;
40 void DynamicApplicationLoader::Load(ApplicationManager
* manager
,
42 scoped_refptr
<LoadCallbacks
> callbacks
) {
44 if (url
.SchemeIs("mojo")) {
45 resolved_url
= context_
->mojo_url_resolver()->Resolve(url
);
50 if (resolved_url
.SchemeIsFile())
51 LoadLocalService(resolved_url
, callbacks
);
53 LoadNetworkService(resolved_url
, callbacks
);
56 void DynamicApplicationLoader::LoadLocalService(
57 const GURL
& resolved_url
,
58 scoped_refptr
<LoadCallbacks
> callbacks
) {
60 net::FileURLToFilePath(resolved_url
, &path
);
61 const bool kDeleteFileAfter
= false;
63 // Async for consistency with network case.
64 base::MessageLoop::current()->PostTask(
66 base::Bind(&DynamicApplicationLoader::RunLibrary
,
67 weak_ptr_factory_
.GetWeakPtr(),
71 base::PathExists(path
)));
74 void DynamicApplicationLoader::LoadNetworkService(
75 const GURL
& resolved_url
,
76 scoped_refptr
<LoadCallbacks
> callbacks
) {
77 if (!network_service_
) {
78 context_
->application_manager()->ConnectToService(
79 GURL("mojo:mojo_network_service"), &network_service_
);
82 network_service_
->CreateURLLoader(Get(&url_loader_
));
84 URLRequestPtr
request(URLRequest::New());
85 request
->url
= String::From(resolved_url
);
86 request
->auto_follow_redirects
= true;
88 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
89 switches::kDisableCache
)) {
90 request
->bypass_cache
= true;
95 base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete
,
96 weak_ptr_factory_
.GetWeakPtr(),
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 "
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());
116 base::CreateTemporaryFile(&file
);
118 const bool kDeleteFileAfter
= true;
119 common::CopyToFile(response
->body
.Pass(),
121 context_
->task_runners()->blocking_pool(),
122 base::Bind(&DynamicApplicationLoader::RunLibrary
,
123 weak_ptr_factory_
.GetWeakPtr(),
129 void DynamicApplicationLoader::RunLibrary(
130 const base::FilePath
& path
,
131 scoped_refptr
<LoadCallbacks
> callbacks
,
132 bool delete_file_after
,
135 ScopedMessagePipeHandle shell_handle
= callbacks
->RegisterApplication();
136 if (!shell_handle
.is_valid())
140 DVLOG(1) << "Library not started because library path '"
141 << path
.value() << "' does not exist.";
145 scoped_ptr
<DynamicServiceRunner
> runner
=
146 runner_factory_
->Create(context_
).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());
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
) {
163 if (!temp_file
.empty())
164 base::DeleteFile(temp_file
, false);
170 void DynamicApplicationLoader::OnApplicationError(ApplicationManager
* manager
,
172 // 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?