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_service_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"
27 explicit Loader(scoped_ptr
<DynamicServiceRunner
> runner
)
28 : runner_(runner
.Pass()) {
31 virtual void Start(const GURL
& url
,
32 ScopedMessagePipeHandle service_handle
,
33 Context
* context
) = 0;
35 void StartService(const base::FilePath
& path
,
36 ScopedMessagePipeHandle service_handle
,
39 runner_
->Start(path
, service_handle
.Pass(),
40 base::Bind(&Loader::AppCompleted
, base::Unretained(this)));
54 scoped_ptr
<DynamicServiceRunner
> runner_
;
57 // For loading services via file:// URLs.
58 class LocalLoader
: public Loader
{
60 explicit LocalLoader(scoped_ptr
<DynamicServiceRunner
> runner
)
61 : Loader(runner
.Pass()) {
64 virtual void Start(const GURL
& url
,
65 ScopedMessagePipeHandle service_handle
,
66 Context
* context
) OVERRIDE
{
68 net::FileURLToFilePath(url
, &path
);
70 // TODO(darin): Check if the given file path exists.
72 // Complete asynchronously for consistency with NetworkServiceLoader.
73 base::MessageLoop::current()->PostTask(
75 base::Bind(&Loader::StartService
,
76 base::Unretained(this),
78 base::Passed(&service_handle
),
83 // For loading services via the network stack.
84 class NetworkLoader
: public Loader
{
86 explicit NetworkLoader(scoped_ptr
<DynamicServiceRunner
> runner
,
87 NetworkService
* network_service
)
88 : Loader(runner
.Pass()) {
89 network_service
->CreateURLLoader(Get(&url_loader_
));
92 virtual void Start(const GURL
& url
,
93 ScopedMessagePipeHandle service_handle
,
94 Context
* context
) OVERRIDE
{
95 service_handle_
= service_handle
.Pass();
98 URLRequestPtr
request(URLRequest::New());
99 request
->url
= String::From(url
);
100 request
->auto_follow_redirects
= true;
102 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
103 switches::kDisableCache
)) {
104 request
->bypass_cache
= true;
107 url_loader_
->Start(request
.Pass(),
108 base::Bind(&NetworkLoader::OnReceivedResponse
,
109 base::Unretained(this)));
113 virtual ~NetworkLoader() {
115 base::DeleteFile(file_
, false);
118 void OnReceivedResponse(URLResponsePtr response
) {
119 if (response
->error
) {
120 LOG(ERROR
) << "Error (" << response
->error
->code
<< ": "
121 << response
->error
->description
<< ") while fetching "
125 base::CreateTemporaryFile(&file_
);
126 common::CopyToFile(response
->body
.Pass(),
128 context_
->task_runners()->blocking_pool(),
129 base::Bind(&Loader::StartService
,
130 base::Unretained(this),
132 base::Passed(&service_handle_
)));
136 NetworkServicePtr network_service_
;
137 URLLoaderPtr url_loader_
;
138 ScopedMessagePipeHandle service_handle_
;
139 base::FilePath file_
;
144 DynamicServiceLoader::DynamicServiceLoader(
146 scoped_ptr
<DynamicServiceRunnerFactory
> runner_factory
)
148 runner_factory_(runner_factory
.Pass()) {
151 DynamicServiceLoader::~DynamicServiceLoader() {
154 void DynamicServiceLoader::LoadService(ServiceManager
* manager
,
156 ScopedMessagePipeHandle shell_handle
) {
157 scoped_ptr
<DynamicServiceRunner
> runner
= runner_factory_
->Create(context_
);
160 if (url
.SchemeIs("mojo")) {
161 resolved_url
= context_
->mojo_url_resolver()->Resolve(url
);
167 if (resolved_url
.SchemeIsFile()) {
168 loader
= new LocalLoader(runner
.Pass());
170 if (!network_service_
.get()) {
171 context_
->service_manager()->ConnectToService(
172 GURL("mojo:mojo_network_service"),
175 loader
= new NetworkLoader(runner
.Pass(), network_service_
.get());
177 loader
->Start(resolved_url
, shell_handle
.Pass(), context_
);
180 void DynamicServiceLoader::OnServiceError(ServiceManager
* manager
,
182 // TODO(darin): What should we do about service errors? This implies that
183 // the app closed its handle to the service manager. Maybe we don't care?