Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/shell/dynamic_application_loader.h" | 5 #include "mojo/shell/dynamic_application_loader.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/format_macros.h" | |
| 12 #include "base/logging.h" | |
| 11 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/memory/weak_ptr.h" | 14 #include "base/memory/weak_ptr.h" |
| 13 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/strings/stringprintf.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 15 #include "mojo/common/common_type_converters.h" | 18 #include "mojo/common/common_type_converters.h" |
| 16 #include "mojo/common/data_pipe_utils.h" | 19 #include "mojo/common/data_pipe_utils.h" |
| 20 #include "mojo/public/cpp/system/data_pipe.h" | |
| 17 #include "mojo/services/public/interfaces/network/url_loader.mojom.h" | 21 #include "mojo/services/public/interfaces/network/url_loader.mojom.h" |
| 18 #include "mojo/shell/context.h" | 22 #include "mojo/shell/context.h" |
| 19 #include "mojo/shell/filename_util.h" | 23 #include "mojo/shell/filename_util.h" |
| 20 #include "mojo/shell/switches.h" | 24 #include "mojo/shell/switches.h" |
| 21 #include "url/url_util.h" | 25 #include "url/url_util.h" |
| 22 | 26 |
| 23 namespace mojo { | 27 namespace mojo { |
| 24 namespace shell { | 28 namespace shell { |
| 25 | 29 |
| 30 namespace { | |
| 31 | |
| 32 void IgnoreResult(bool result) { | |
| 33 } | |
| 34 | |
| 35 class LoaderResponse { | |
|
Aaron Boodman
2014/11/03 19:20:15
Is there some better way to factor this?
It seems
qsr
2014/11/04 11:58:34
Not easily. But I can definitively make this class
Aaron Boodman
2014/11/04 18:05:01
Really? It seems like all the methods of this clas
qsr
2014/11/05 10:21:54
We could do this, but it would mean adding the fie
| |
| 36 public: | |
| 37 explicit LoaderResponse(URLResponsePtr response) | |
| 38 : file_needs_cleanup_(true), response_(response.Pass()) {} | |
| 39 LoaderResponse(const GURL& url, base::FilePath path) | |
| 40 : file_needs_cleanup_(false), url_(url), path_(path) {} | |
| 41 | |
| 42 ~LoaderResponse() { | |
| 43 if (file_needs_cleanup_ && !path_.empty()) | |
| 44 base::DeleteFile(path_, false); | |
| 45 } | |
| 46 | |
| 47 URLResponsePtr AsURLResponse(base::TaskRunner* task_runner) { | |
| 48 if (response_ || path_.empty()) | |
| 49 return response_.Pass(); | |
| 50 URLResponsePtr response(URLResponse::New()); | |
| 51 response->url = String::From(url_); | |
| 52 DataPipe data_pipe; | |
| 53 response->body = data_pipe.consumer_handle.Pass(); | |
| 54 int64 file_size; | |
| 55 if (base::GetFileSize(path_, &file_size)) { | |
| 56 response->headers = Array<String>(1); | |
| 57 response->headers[0] = | |
| 58 base::StringPrintf("Content-Length: %" PRId64, file_size); | |
| 59 } | |
| 60 common::CopyFromFile(path_, | |
| 61 data_pipe.producer_handle.Pass(), | |
| 62 task_runner, | |
| 63 base::Bind(&IgnoreResult)); | |
|
Aaron Boodman
2014/11/04 18:05:00
I think you can also do this?
base::Callback<void
qsr
2014/11/05 10:21:54
Not really. See the comment in base/task_runner_ut
| |
| 64 return response.Pass(); | |
| 65 } | |
| 66 | |
| 67 void AsPath(base::TaskRunner* task_runner, | |
| 68 base::Callback<void(const base::FilePath&, bool)> callback) { | |
| 69 if (!path_.empty() || !response_) { | |
| 70 callback.Run(path_, base::PathExists(path_)); | |
| 71 return; | |
| 72 } | |
| 73 base::CreateTemporaryFile(&path_); | |
| 74 common::CopyToFile(response_->body.Pass(), | |
| 75 path_, | |
| 76 task_runner, | |
| 77 base::Bind(callback, path_)); | |
| 78 } | |
| 79 | |
| 80 std::string MimeType() { | |
| 81 if (response_) | |
| 82 return response_->mime_type; | |
| 83 return ""; | |
| 84 } | |
| 85 | |
| 86 std::string Url() { | |
| 87 if (response_) | |
| 88 return response_->url; | |
| 89 return String::From(url_); | |
| 90 } | |
| 91 | |
| 92 private: | |
| 93 bool file_needs_cleanup_; | |
| 94 URLResponsePtr response_; | |
| 95 GURL url_; | |
| 96 base::FilePath path_; | |
| 97 }; | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 26 // Encapsulates loading and running one individual application. | 101 // Encapsulates loading and running one individual application. |
| 27 // | 102 // |
| 28 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must | 103 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must |
| 29 // ensure that all the parameters passed to Loader subclasses stay valid through | 104 // ensure that all the parameters passed to Loader subclasses stay valid through |
| 30 // Loader's lifetime. | 105 // Loader's lifetime. |
| 31 // | 106 // |
| 32 // Async operations are done with WeakPtr to protect against | 107 // Async operations are done with WeakPtr to protect against |
| 33 // DynamicApplicationLoader going away (and taking all the Loaders with it) | 108 // DynamicApplicationLoader going away (and taking all the Loaders with it) |
| 34 // while the async operation is outstanding. | 109 // while the async operation is outstanding. |
| 35 class DynamicApplicationLoader::Loader { | 110 class DynamicApplicationLoader::Loader { |
| 36 public: | 111 public: |
| 37 Loader(Context* context, | 112 Loader(Context* context, |
| 113 MimeTypeToURLMap* mime_type_to_url, | |
| 38 DynamicServiceRunnerFactory* runner_factory, | 114 DynamicServiceRunnerFactory* runner_factory, |
| 39 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | 115 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
| 40 const LoaderCompleteCallback& loader_complete_callback) | 116 const LoaderCompleteCallback& loader_complete_callback) |
| 41 : load_callbacks_(load_callbacks), | 117 : load_callbacks_(load_callbacks), |
| 42 loader_complete_callback_(loader_complete_callback), | 118 loader_complete_callback_(loader_complete_callback), |
| 43 context_(context), | 119 context_(context), |
| 120 mime_type_to_url_(mime_type_to_url), | |
| 44 runner_factory_(runner_factory), | 121 runner_factory_(runner_factory), |
| 45 weak_ptr_factory_(this) {} | 122 weak_ptr_factory_(this) {} |
| 46 | 123 |
| 47 virtual ~Loader() {} | 124 virtual ~Loader() {} |
| 48 | 125 |
| 49 protected: | 126 protected: |
| 50 void RunLibrary(const base::FilePath& path, bool path_exists) { | 127 void RunLibrary(const base::FilePath& path, bool path_exists) { |
| 51 ScopedMessagePipeHandle shell_handle = | 128 ScopedMessagePipeHandle shell_handle = |
| 52 load_callbacks_->RegisterApplication(); | 129 load_callbacks_->RegisterApplication(); |
| 53 if (!shell_handle.is_valid()) { | 130 if (!shell_handle.is_valid()) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 64 | 141 |
| 65 runner_ = runner_factory_->Create(context_); | 142 runner_ = runner_factory_->Create(context_); |
| 66 runner_->Start( | 143 runner_->Start( |
| 67 path, | 144 path, |
| 68 shell_handle.Pass(), | 145 shell_handle.Pass(), |
| 69 base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr())); | 146 base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr())); |
| 70 } | 147 } |
| 71 | 148 |
| 72 void LoaderComplete() { loader_complete_callback_.Run(this); } | 149 void LoaderComplete() { loader_complete_callback_.Run(this); } |
| 73 | 150 |
| 151 void OnResponse(scoped_ptr<LoaderResponse> response) { | |
| 152 MimeTypeToURLMap::iterator iter = | |
| 153 mime_type_to_url_->find(response->MimeType()); | |
| 154 if (iter != mime_type_to_url_->end()) { | |
| 155 load_callbacks_->LoadWithContentHandler( | |
| 156 iter->second, | |
| 157 response->AsURLResponse(context_->task_runners()->blocking_pool())); | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 LOG(INFO) << "Failed to find content handler for " << response->Url() | |
| 162 << " (mimetype: " << response->MimeType() << ")" << std::endl | |
| 163 << "Attempting to load as native library instead..."; | |
| 164 | |
| 165 // TODO(aa): Santify check that the thing we got looks vaguely like a mojo | |
| 166 // application. That could either mean looking for the platform-specific dll | |
| 167 // header, or looking for some specific mojo signature prepended to the | |
| 168 // library. | |
| 169 | |
| 170 response->AsPath( | |
| 171 context_->task_runners()->blocking_pool(), | |
| 172 base::Bind(&Loader::RunLibrary, weak_ptr_factory_.GetWeakPtr())); | |
| 173 } | |
| 174 | |
| 74 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_; | 175 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_; |
| 75 LoaderCompleteCallback loader_complete_callback_; | 176 LoaderCompleteCallback loader_complete_callback_; |
| 76 Context* context_; | 177 Context* context_; |
| 178 MimeTypeToURLMap* mime_type_to_url_; | |
| 77 | 179 |
| 78 private: | 180 private: |
| 79 DynamicServiceRunnerFactory* runner_factory_; | 181 DynamicServiceRunnerFactory* runner_factory_; |
| 80 scoped_ptr<DynamicServiceRunner> runner_; | 182 scoped_ptr<DynamicServiceRunner> runner_; |
| 81 base::WeakPtrFactory<Loader> weak_ptr_factory_; | 183 base::WeakPtrFactory<Loader> weak_ptr_factory_; |
| 82 }; | 184 }; |
| 83 | 185 |
| 84 // A loader for local files. | 186 // A loader for local files. |
| 85 class DynamicApplicationLoader::LocalLoader : public Loader { | 187 class DynamicApplicationLoader::LocalLoader : public Loader { |
| 86 public: | 188 public: |
| 87 LocalLoader(const GURL& url, | 189 LocalLoader(const GURL& url, |
| 88 Context* context, | 190 Context* context, |
| 191 MimeTypeToURLMap* mime_type_to_url, | |
| 89 DynamicServiceRunnerFactory* runner_factory, | 192 DynamicServiceRunnerFactory* runner_factory, |
| 90 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | 193 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
| 91 const LoaderCompleteCallback& loader_complete_callback) | 194 const LoaderCompleteCallback& loader_complete_callback) |
| 92 : Loader(context, | 195 : Loader(context, |
| 196 mime_type_to_url, | |
| 93 runner_factory, | 197 runner_factory, |
| 94 load_callbacks, | 198 load_callbacks, |
| 95 loader_complete_callback), | 199 loader_complete_callback) { |
| 96 weak_ptr_factory_(this) { | |
| 97 DCHECK(url.SchemeIsFile()); | 200 DCHECK(url.SchemeIsFile()); |
| 98 url::RawCanonOutputW<1024> output; | 201 url::RawCanonOutputW<1024> output; |
| 99 url::DecodeURLEscapeSequences( | 202 url::DecodeURLEscapeSequences( |
| 100 url.path().data(), static_cast<int>(url.path().length()), &output); | 203 url.path().data(), static_cast<int>(url.path().length()), &output); |
| 101 base::string16 decoded_path = | 204 base::string16 decoded_path = |
| 102 base::string16(output.data(), output.length()); | 205 base::string16(output.data(), output.length()); |
| 103 #if defined(OS_WIN) | 206 #if defined(OS_WIN) |
| 104 base::FilePath path(decoded_path); | 207 base::FilePath path(decoded_path); |
| 105 #else | 208 #else |
| 106 base::FilePath path(base::UTF16ToUTF8(decoded_path)); | 209 base::FilePath path(base::UTF16ToUTF8(decoded_path)); |
| 107 #endif | 210 #endif |
| 108 | 211 |
| 109 // Async for consistency with network case. | 212 OnResponse(make_scoped_ptr(new LoaderResponse(url, path))); |
| 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 } | 213 } |
| 117 | 214 |
| 118 ~LocalLoader() override {} | 215 ~LocalLoader() override {} |
| 119 | |
| 120 private: | |
| 121 base::WeakPtrFactory<LocalLoader> weak_ptr_factory_; | |
| 122 }; | 216 }; |
| 123 | 217 |
| 124 // A loader for network files. | 218 // A loader for network files. |
| 125 class DynamicApplicationLoader::NetworkLoader : public Loader { | 219 class DynamicApplicationLoader::NetworkLoader : public Loader { |
| 126 public: | 220 public: |
| 127 NetworkLoader(const GURL& url, | 221 NetworkLoader(const GURL& url, |
| 128 MimeTypeToURLMap* mime_type_to_url, | 222 MimeTypeToURLMap* mime_type_to_url, |
| 129 Context* context, | 223 Context* context, |
| 130 DynamicServiceRunnerFactory* runner_factory, | 224 DynamicServiceRunnerFactory* runner_factory, |
| 131 NetworkService* network_service, | 225 NetworkService* network_service, |
| 132 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, | 226 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
| 133 const LoaderCompleteCallback& loader_complete_callback) | 227 const LoaderCompleteCallback& loader_complete_callback) |
| 134 : Loader(context, | 228 : Loader(context, |
| 229 mime_type_to_url, | |
| 135 runner_factory, | 230 runner_factory, |
| 136 load_callbacks, | 231 load_callbacks, |
| 137 loader_complete_callback), | 232 loader_complete_callback), |
| 138 mime_type_to_url_(mime_type_to_url), | |
| 139 weak_ptr_factory_(this) { | 233 weak_ptr_factory_(this) { |
| 140 URLRequestPtr request(URLRequest::New()); | 234 URLRequestPtr request(URLRequest::New()); |
| 141 request->url = String::From(url); | 235 request->url = String::From(url); |
| 142 request->auto_follow_redirects = true; | 236 request->auto_follow_redirects = true; |
| 143 | 237 |
| 144 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 238 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 145 switches::kDisableCache)) { | 239 switches::kDisableCache)) { |
| 146 request->bypass_cache = true; | 240 request->bypass_cache = true; |
| 147 } | 241 } |
| 148 | 242 |
| 149 network_service->CreateURLLoader(GetProxy(&url_loader_)); | 243 network_service->CreateURLLoader(GetProxy(&url_loader_)); |
| 150 url_loader_->Start(request.Pass(), | 244 url_loader_->Start(request.Pass(), |
| 151 base::Bind(&NetworkLoader::OnLoadComplete, | 245 base::Bind(&NetworkLoader::OnLoadComplete, |
| 152 weak_ptr_factory_.GetWeakPtr())); | 246 weak_ptr_factory_.GetWeakPtr())); |
| 153 } | 247 } |
| 154 | 248 |
| 155 ~NetworkLoader() override { | |
| 156 if (!file_.empty()) | |
| 157 base::DeleteFile(file_, false); | |
| 158 } | |
| 159 | |
| 160 private: | 249 private: |
| 161 void OnLoadComplete(URLResponsePtr response) { | 250 void OnLoadComplete(URLResponsePtr response) { |
| 162 if (response->error) { | 251 if (response->error) { |
| 163 LOG(ERROR) << "Error (" << response->error->code << ": " | 252 LOG(ERROR) << "Error (" << response->error->code << ": " |
| 164 << response->error->description << ") while fetching " | 253 << response->error->description << ") while fetching " |
| 165 << response->url; | 254 << response->url; |
| 166 LoaderComplete(); | 255 LoaderComplete(); |
| 167 return; | 256 return; |
| 168 } | 257 } |
| 169 | 258 |
| 170 MimeTypeToURLMap::iterator iter = | 259 OnResponse(make_scoped_ptr(new LoaderResponse(response.Pass()))); |
| 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 LOG(INFO) << "Failed to find content handler for " << response->url | |
| 178 << " (mimetype: " << response->url << ")" << std::endl | |
| 179 << "Attempting to load as native library instead..."; | |
| 180 | |
| 181 // TODO(aa): Santify check that the thing we got looks vaguely like a mojo | |
| 182 // application. That could either mean looking for the platform-specific dll | |
| 183 // header, or looking for some specific mojo signature prepended to the | |
| 184 // library. | |
| 185 | |
| 186 base::CreateTemporaryFile(&file_); | |
| 187 common::CopyToFile( | |
| 188 response->body.Pass(), | |
| 189 file_, | |
| 190 context_->task_runners()->blocking_pool(), | |
| 191 base::Bind( | |
| 192 &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_)); | |
| 193 } | 260 } |
| 194 | 261 |
| 195 MimeTypeToURLMap* mime_type_to_url_; | |
| 196 URLLoaderPtr url_loader_; | 262 URLLoaderPtr url_loader_; |
| 197 base::FilePath file_; | |
| 198 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_; | 263 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_; |
| 199 }; | 264 }; |
| 200 | 265 |
| 201 DynamicApplicationLoader::DynamicApplicationLoader( | 266 DynamicApplicationLoader::DynamicApplicationLoader( |
| 202 Context* context, | 267 Context* context, |
| 203 scoped_ptr<DynamicServiceRunnerFactory> runner_factory) | 268 scoped_ptr<DynamicServiceRunnerFactory> runner_factory) |
| 204 : context_(context), | 269 : context_(context), |
| 205 runner_factory_(runner_factory.Pass()), | 270 runner_factory_(runner_factory.Pass()), |
| 206 | 271 |
| 207 // Unretained() is correct here because DynamicApplicationLoader owns the | 272 // Unretained() is correct here because DynamicApplicationLoader owns the |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 227 GURL resolved_url; | 292 GURL resolved_url; |
| 228 if (url.SchemeIs("mojo")) { | 293 if (url.SchemeIs("mojo")) { |
| 229 resolved_url = context_->mojo_url_resolver()->Resolve(url); | 294 resolved_url = context_->mojo_url_resolver()->Resolve(url); |
| 230 } else { | 295 } else { |
| 231 resolved_url = url; | 296 resolved_url = url; |
| 232 } | 297 } |
| 233 | 298 |
| 234 if (resolved_url.SchemeIsFile()) { | 299 if (resolved_url.SchemeIsFile()) { |
| 235 loaders_.push_back(new LocalLoader(resolved_url, | 300 loaders_.push_back(new LocalLoader(resolved_url, |
| 236 context_, | 301 context_, |
| 302 &mime_type_to_url_, | |
| 237 runner_factory_.get(), | 303 runner_factory_.get(), |
| 238 load_callbacks, | 304 load_callbacks, |
| 239 loader_complete_callback_)); | 305 loader_complete_callback_)); |
| 240 return; | 306 return; |
| 241 } | 307 } |
| 242 | 308 |
| 243 if (!network_service_) { | 309 if (!network_service_) { |
| 244 context_->application_manager()->ConnectToService( | 310 context_->application_manager()->ConnectToService( |
| 245 GURL("mojo:network_service"), &network_service_); | 311 GURL("mojo:network_service"), &network_service_); |
| 246 } | 312 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 259 // TODO(darin): What should we do about service errors? This implies that | 325 // TODO(darin): What should we do about service errors? This implies that |
| 260 // the app closed its handle to the service manager. Maybe we don't care? | 326 // the app closed its handle to the service manager. Maybe we don't care? |
| 261 } | 327 } |
| 262 | 328 |
| 263 void DynamicApplicationLoader::LoaderComplete(Loader* loader) { | 329 void DynamicApplicationLoader::LoaderComplete(Loader* loader) { |
| 264 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); | 330 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); |
| 265 } | 331 } |
| 266 | 332 |
| 267 } // namespace shell | 333 } // namespace shell |
| 268 } // namespace mojo | 334 } // namespace mojo |
| OLD | NEW |