| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "mojo/shell/dynamic_application_loader.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/files/file_util.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/memory/weak_ptr.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | |
| 15 #include "mojo/common/common_type_converters.h" | |
| 16 #include "mojo/common/data_pipe_utils.h" | |
| 17 #include "mojo/services/public/interfaces/network/url_loader.mojom.h" | |
| 18 #include "mojo/shell/context.h" | |
| 19 #include "mojo/shell/filename_util.h" | |
| 20 #include "mojo/shell/switches.h" | |
| 21 #include "url/url_util.h" | |
| 22 | |
| 23 namespace mojo { | |
| 24 namespace shell { | |
| 25 | |
| 26 // Encapsulates loading and running one individual application. | |
| 27 // | |
| 28 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must | |
| 29 // ensure that all the parameters passed to Loader subclasses stay valid through | |
| 30 // Loader's lifetime. | |
| 31 // | |
| 32 // Async operations are done with WeakPtr to protect against | |
| 33 // DynamicApplicationLoader going away (and taking all the Loaders with it) | |
| 34 // while the async operation is outstanding. | |
| 35 class DynamicApplicationLoader::Loader { | |
| 36 public: | |
| 37 Loader(Context* context, | |
| 38 DynamicServiceRunnerFactory* runner_factory, | |
| 39 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | |
| 40 const LoaderCompleteCallback& loader_complete_callback) | |
| 41 : load_callbacks_(load_callbacks), | |
| 42 loader_complete_callback_(loader_complete_callback), | |
| 43 context_(context), | |
| 44 runner_factory_(runner_factory), | |
| 45 weak_ptr_factory_(this) {} | |
| 46 | |
| 47 virtual ~Loader() {} | |
| 48 | |
| 49 protected: | |
| 50 void RunLibrary(const base::FilePath& path, bool path_exists) { | |
| 51 ScopedMessagePipeHandle shell_handle = | |
| 52 load_callbacks_->RegisterApplication(); | |
| 53 if (!shell_handle.is_valid()) { | |
| 54 LoaderComplete(); | |
| 55 return; | |
| 56 } | |
| 57 | |
| 58 if (!path_exists) { | |
| 59 DVLOG(1) << "Library not started because library path '" << path.value() | |
| 60 << "' does not exist."; | |
| 61 LoaderComplete(); | |
| 62 return; | |
| 63 } | |
| 64 | |
| 65 runner_ = runner_factory_->Create(context_); | |
| 66 runner_->Start( | |
| 67 path, | |
| 68 shell_handle.Pass(), | |
| 69 base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr())); | |
| 70 } | |
| 71 | |
| 72 void LoaderComplete() { loader_complete_callback_.Run(this); } | |
| 73 | |
| 74 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_; | |
| 75 LoaderCompleteCallback loader_complete_callback_; | |
| 76 Context* context_; | |
| 77 | |
| 78 private: | |
| 79 DynamicServiceRunnerFactory* runner_factory_; | |
| 80 scoped_ptr<DynamicServiceRunner> runner_; | |
| 81 base::WeakPtrFactory<Loader> weak_ptr_factory_; | |
| 82 }; | |
| 83 | |
| 84 // A loader for local files. | |
| 85 class DynamicApplicationLoader::LocalLoader : public Loader { | |
| 86 public: | |
| 87 LocalLoader(const GURL& url, | |
| 88 Context* context, | |
| 89 DynamicServiceRunnerFactory* runner_factory, | |
| 90 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | |
| 91 const LoaderCompleteCallback& loader_complete_callback) | |
| 92 : Loader(context, | |
| 93 runner_factory, | |
| 94 load_callbacks, | |
| 95 loader_complete_callback), | |
| 96 weak_ptr_factory_(this) { | |
| 97 DCHECK(url.SchemeIsFile()); | |
| 98 url::RawCanonOutputW<1024> output; | |
| 99 url::DecodeURLEscapeSequences( | |
| 100 url.path().data(), static_cast<int>(url.path().length()), &output); | |
| 101 base::string16 decoded_path = | |
| 102 base::string16(output.data(), output.length()); | |
| 103 #if defined(OS_WIN) | |
| 104 base::FilePath path(decoded_path); | |
| 105 #else | |
| 106 base::FilePath path(base::UTF16ToUTF8(decoded_path)); | |
| 107 #endif | |
| 108 | |
| 109 // Async for consistency with network case. | |
| 110 base::MessageLoop::current()->PostTask( | |
| 111 FROM_HERE, | |
| 112 base::Bind(&LocalLoader::RunLibrary, | |
| 113 weak_ptr_factory_.GetWeakPtr(), | |
| 114 path, | |
| 115 base::PathExists(path))); | |
| 116 } | |
| 117 | |
| 118 ~LocalLoader() override {} | |
| 119 | |
| 120 private: | |
| 121 base::WeakPtrFactory<LocalLoader> weak_ptr_factory_; | |
| 122 }; | |
| 123 | |
| 124 // A loader for network files. | |
| 125 class DynamicApplicationLoader::NetworkLoader : public Loader { | |
| 126 public: | |
| 127 NetworkLoader(const GURL& url, | |
| 128 MimeTypeToURLMap* mime_type_to_url, | |
| 129 Context* context, | |
| 130 DynamicServiceRunnerFactory* runner_factory, | |
| 131 NetworkService* network_service, | |
| 132 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | |
| 133 const LoaderCompleteCallback& loader_complete_callback) | |
| 134 : Loader(context, | |
| 135 runner_factory, | |
| 136 load_callbacks, | |
| 137 loader_complete_callback), | |
| 138 mime_type_to_url_(mime_type_to_url), | |
| 139 weak_ptr_factory_(this) { | |
| 140 URLRequestPtr request(URLRequest::New()); | |
| 141 request->url = String::From(url); | |
| 142 request->auto_follow_redirects = true; | |
| 143 | |
| 144 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 145 switches::kDisableCache)) { | |
| 146 request->bypass_cache = true; | |
| 147 } | |
| 148 | |
| 149 network_service->CreateURLLoader(GetProxy(&url_loader_)); | |
| 150 url_loader_->Start(request.Pass(), | |
| 151 base::Bind(&NetworkLoader::OnLoadComplete, | |
| 152 weak_ptr_factory_.GetWeakPtr())); | |
| 153 } | |
| 154 | |
| 155 ~NetworkLoader() override { | |
| 156 if (!file_.empty()) | |
| 157 base::DeleteFile(file_, false); | |
| 158 } | |
| 159 | |
| 160 private: | |
| 161 void OnLoadComplete(URLResponsePtr response) { | |
| 162 if (response->error) { | |
| 163 LOG(ERROR) << "Error (" << response->error->code << ": " | |
| 164 << response->error->description << ") while fetching " | |
| 165 << response->url; | |
| 166 LoaderComplete(); | |
| 167 return; | |
| 168 } | |
| 169 | |
| 170 MimeTypeToURLMap::iterator iter = | |
| 171 mime_type_to_url_->find(response->mime_type); | |
| 172 if (iter != mime_type_to_url_->end()) { | |
| 173 load_callbacks_->LoadWithContentHandler(iter->second, response.Pass()); | |
| 174 return; | |
| 175 } | |
| 176 | |
| 177 base::CreateTemporaryFile(&file_); | |
| 178 common::CopyToFile( | |
| 179 response->body.Pass(), | |
| 180 file_, | |
| 181 context_->task_runners()->blocking_pool(), | |
| 182 base::Bind( | |
| 183 &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_)); | |
| 184 } | |
| 185 | |
| 186 MimeTypeToURLMap* mime_type_to_url_; | |
| 187 URLLoaderPtr url_loader_; | |
| 188 base::FilePath file_; | |
| 189 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_; | |
| 190 }; | |
| 191 | |
| 192 DynamicApplicationLoader::DynamicApplicationLoader( | |
| 193 Context* context, | |
| 194 scoped_ptr<DynamicServiceRunnerFactory> runner_factory) | |
| 195 : context_(context), | |
| 196 runner_factory_(runner_factory.Pass()), | |
| 197 | |
| 198 // Unretained() is correct here because DynamicApplicationLoader owns the | |
| 199 // loaders that we pass this callback to. | |
| 200 loader_complete_callback_( | |
| 201 base::Bind(&DynamicApplicationLoader::LoaderComplete, | |
| 202 base::Unretained(this))) { | |
| 203 } | |
| 204 | |
| 205 DynamicApplicationLoader::~DynamicApplicationLoader() { | |
| 206 } | |
| 207 | |
| 208 void DynamicApplicationLoader::RegisterContentHandler( | |
| 209 const std::string& mime_type, | |
| 210 const GURL& content_handler_url) { | |
| 211 mime_type_to_url_[mime_type] = content_handler_url; | |
| 212 } | |
| 213 | |
| 214 void DynamicApplicationLoader::Load( | |
| 215 ApplicationManager* manager, | |
| 216 const GURL& url, | |
| 217 scoped_refptr<LoadCallbacks> load_callbacks) { | |
| 218 GURL resolved_url; | |
| 219 if (url.SchemeIs("mojo")) { | |
| 220 resolved_url = context_->mojo_url_resolver()->Resolve(url); | |
| 221 } else { | |
| 222 resolved_url = url; | |
| 223 } | |
| 224 | |
| 225 if (resolved_url.SchemeIsFile()) { | |
| 226 loaders_.push_back(new LocalLoader(resolved_url, | |
| 227 context_, | |
| 228 runner_factory_.get(), | |
| 229 load_callbacks, | |
| 230 loader_complete_callback_)); | |
| 231 return; | |
| 232 } | |
| 233 | |
| 234 if (!network_service_) { | |
| 235 context_->application_manager()->ConnectToService( | |
| 236 GURL("mojo:network_service"), &network_service_); | |
| 237 } | |
| 238 | |
| 239 loaders_.push_back(new NetworkLoader(resolved_url, | |
| 240 &mime_type_to_url_, | |
| 241 context_, | |
| 242 runner_factory_.get(), | |
| 243 network_service_.get(), | |
| 244 load_callbacks, | |
| 245 loader_complete_callback_)); | |
| 246 } | |
| 247 | |
| 248 void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager, | |
| 249 const GURL& url) { | |
| 250 // TODO(darin): What should we do about service errors? This implies that | |
| 251 // the app closed its handle to the service manager. Maybe we don't care? | |
| 252 } | |
| 253 | |
| 254 void DynamicApplicationLoader::LoaderComplete(Loader* loader) { | |
| 255 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); | |
| 256 } | |
| 257 | |
| 258 } // namespace shell | |
| 259 } // namespace mojo | |
| OLD | NEW |