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 "shell/application_manager/application_manager.h" | 5 #include "shell/application_manager/application_manager.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/strings/string_util.h" | |
| 14 #include "mojo/public/cpp/bindings/binding.h" | 15 #include "mojo/public/cpp/bindings/binding.h" |
| 15 #include "mojo/public/cpp/bindings/error_handler.h" | 16 #include "mojo/public/cpp/bindings/error_handler.h" |
| 16 #include "mojo/public/interfaces/application/shell.mojom.h" | 17 #include "mojo/public/interfaces/application/shell.mojom.h" |
| 17 #include "mojo/services/content_handler/public/interfaces/content_handler.mojom. h" | 18 #include "mojo/services/content_handler/public/interfaces/content_handler.mojom. h" |
| 18 #include "shell/application_manager/fetcher.h" | 19 #include "shell/application_manager/fetcher.h" |
| 19 #include "shell/application_manager/local_fetcher.h" | 20 #include "shell/application_manager/local_fetcher.h" |
| 20 #include "shell/application_manager/network_fetcher.h" | 21 #include "shell/application_manager/network_fetcher.h" |
| 21 | 22 |
| 22 namespace mojo { | 23 namespace mojo { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 // Used by TestAPI. | 26 // Used by TestAPI. |
| 26 bool has_created_instance = false; | 27 bool has_created_instance = false; |
| 28 | |
| 29 GURL StripQueryFromURL(const GURL& url) { | |
| 30 GURL::Replacements repl; | |
| 31 repl.SetQueryStr(""); | |
| 32 std::string result = url.ReplaceComponents(repl).spec(); | |
| 33 | |
| 34 // Remove the dangling '?' because it's ugly. | |
| 35 base::ReplaceChars(result, "?", "", &result); | |
| 36 return GURL(result); | |
| 37 } | |
| 38 | |
| 27 } // namespace | 39 } // namespace |
| 28 | 40 |
| 29 ApplicationManager::Delegate::~Delegate() { | 41 ApplicationManager::Delegate::~Delegate() { |
| 30 } | 42 } |
| 31 | 43 |
| 32 void ApplicationManager::Delegate::OnApplicationError(const GURL& url) { | 44 void ApplicationManager::Delegate::OnApplicationError(const GURL& url) { |
| 33 LOG(ERROR) << "Communication error with application: " << url.spec(); | 45 LOG(ERROR) << "Communication error with application: " << url.spec(); |
| 34 } | 46 } |
| 35 | 47 |
| 36 GURL ApplicationManager::Delegate::ResolveURL(const GURL& url) { | 48 GURL ApplicationManager::Delegate::ResolveURL(const GURL& url) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 const GURL& requested_url, | 118 const GURL& requested_url, |
| 107 const GURL& requestor_url, | 119 const GURL& requestor_url, |
| 108 InterfaceRequest<ServiceProvider> services, | 120 InterfaceRequest<ServiceProvider> services, |
| 109 ServiceProviderPtr exposed_services) { | 121 ServiceProviderPtr exposed_services) { |
| 110 DCHECK(requested_url.is_valid()); | 122 DCHECK(requested_url.is_valid()); |
| 111 | 123 |
| 112 // We check both the mapped and resolved urls for existing shell_impls because | 124 // We check both the mapped and resolved urls for existing shell_impls because |
| 113 // external applications can be registered for the unresolved mojo:foo urls. | 125 // external applications can be registered for the unresolved mojo:foo urls. |
| 114 | 126 |
| 115 GURL mapped_url = delegate_->ResolveMappings(requested_url); | 127 GURL mapped_url = delegate_->ResolveMappings(requested_url); |
| 116 if (ConnectToRunningApplication(mapped_url, requestor_url, &services, | 128 if (ConnectToRunningApplication(requested_url, mapped_url, requestor_url, |
|
qsr
2015/02/27 15:01:41
I think the URL that the application see should be
Aaron Boodman
2015/02/27 16:54:44
Done.
| |
| 117 &exposed_services)) { | 129 &services, &exposed_services)) { |
| 118 return; | 130 return; |
| 119 } | 131 } |
| 120 | 132 |
| 121 GURL resolved_url = delegate_->ResolveURL(mapped_url); | 133 GURL resolved_url = delegate_->ResolveURL(mapped_url); |
| 122 if (ConnectToRunningApplication(resolved_url, requestor_url, &services, | 134 if (ConnectToRunningApplication(requested_url, resolved_url, requestor_url, |
| 123 &exposed_services)) { | 135 &services, &exposed_services)) { |
| 124 return; | 136 return; |
| 125 } | 137 } |
| 126 | 138 |
| 127 if (ConnectToApplicationWithLoader(requested_url, mapped_url, requestor_url, | 139 if (ConnectToApplicationWithLoader(requested_url, mapped_url, requestor_url, |
| 128 &services, &exposed_services, | 140 &services, &exposed_services, |
| 129 GetLoaderForURL(mapped_url))) { | 141 GetLoaderForURL(mapped_url))) { |
| 130 return; | 142 return; |
| 131 } | 143 } |
| 132 | 144 |
| 133 if (ConnectToApplicationWithLoader(requested_url, resolved_url, requestor_url, | 145 if (ConnectToApplicationWithLoader(requested_url, resolved_url, requestor_url, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 154 } | 166 } |
| 155 | 167 |
| 156 if (!network_service_) | 168 if (!network_service_) |
| 157 ConnectToService(GURL("mojo:network_service"), &network_service_); | 169 ConnectToService(GURL("mojo:network_service"), &network_service_); |
| 158 | 170 |
| 159 new NetworkFetcher(disable_cache_, resolved_url, network_service_.get(), | 171 new NetworkFetcher(disable_cache_, resolved_url, network_service_.get(), |
| 160 base::Bind(callback, NativeRunner::DeleteAppPath)); | 172 base::Bind(callback, NativeRunner::DeleteAppPath)); |
| 161 } | 173 } |
| 162 | 174 |
| 163 bool ApplicationManager::ConnectToRunningApplication( | 175 bool ApplicationManager::ConnectToRunningApplication( |
| 176 const GURL& requested_url, | |
| 164 const GURL& application_url, | 177 const GURL& application_url, |
| 165 const GURL& requestor_url, | 178 const GURL& requestor_url, |
| 166 InterfaceRequest<ServiceProvider>* services, | 179 InterfaceRequest<ServiceProvider>* services, |
| 167 ServiceProviderPtr* exposed_services) { | 180 ServiceProviderPtr* exposed_services) { |
| 168 ShellImpl* shell_impl = GetShellImpl(application_url); | 181 ShellImpl* shell_impl = GetShellImpl(application_url); |
|
qsr
2015/02/27 15:01:41
Any reason you do not always strip the query here?
Aaron Boodman
2015/02/27 16:54:44
Done.
| |
| 169 if (!shell_impl) | 182 if (!shell_impl) { |
| 170 return false; | 183 shell_impl = GetShellImpl(StripQueryFromURL(application_url)); |
| 184 if (!shell_impl || !shell_impl->handles_query()) | |
| 185 return false; | |
| 186 } | |
| 171 | 187 |
| 172 ConnectToClient(shell_impl, application_url, requestor_url, services->Pass(), | 188 ConnectToClient(shell_impl, requested_url, application_url, requestor_url, |
| 173 exposed_services->Pass()); | 189 services->Pass(), exposed_services->Pass()); |
| 174 return true; | 190 return true; |
| 175 } | 191 } |
| 176 | 192 |
| 177 bool ApplicationManager::ConnectToApplicationWithLoader( | 193 bool ApplicationManager::ConnectToApplicationWithLoader( |
| 178 const GURL& requested_url, | 194 const GURL& requested_url, |
| 179 const GURL& resolved_url, | 195 const GURL& resolved_url, |
| 180 const GURL& requestor_url, | 196 const GURL& requestor_url, |
| 181 InterfaceRequest<ServiceProvider>* services, | 197 InterfaceRequest<ServiceProvider>* services, |
| 182 ServiceProviderPtr* exposed_services, | 198 ServiceProviderPtr* exposed_services, |
| 183 ApplicationLoader* loader) { | 199 ApplicationLoader* loader) { |
| 184 if (!loader) | 200 if (!loader) |
| 185 return false; | 201 return false; |
| 186 | 202 |
| 187 loader->Load(resolved_url, | 203 loader->Load(resolved_url, |
| 188 RegisterShell(requested_url, resolved_url, requestor_url, | 204 RegisterShell(requested_url, resolved_url, requestor_url, |
| 189 services->Pass(), exposed_services->Pass())); | 205 services->Pass(), exposed_services->Pass(), |
| 206 ShellImpl::SHELL_DOES_NOT_HANDLE_QUERY)); | |
| 190 return true; | 207 return true; |
| 191 } | 208 } |
| 192 | 209 |
| 193 InterfaceRequest<Application> ApplicationManager::RegisterShell( | 210 InterfaceRequest<Application> ApplicationManager::RegisterShell( |
| 194 const GURL& requested_url, | 211 const GURL& requested_url, |
| 195 const GURL& resolved_url, | 212 GURL resolved_url, |
| 196 const GURL& requestor_url, | 213 const GURL& requestor_url, |
| 197 InterfaceRequest<ServiceProvider> services, | 214 InterfaceRequest<ServiceProvider> services, |
| 198 ServiceProviderPtr exposed_services) { | 215 ServiceProviderPtr exposed_services, |
| 216 ShellImpl::QueryHandlingBehavior query_behavior) { | |
| 217 if (query_behavior == ShellImpl::SHELL_HANDLES_QUERY) | |
| 218 resolved_url = StripQueryFromURL(resolved_url); | |
| 219 | |
| 199 ApplicationPtr application; | 220 ApplicationPtr application; |
| 200 InterfaceRequest<Application> application_request = GetProxy(&application); | 221 InterfaceRequest<Application> application_request = GetProxy(&application); |
| 201 ShellImpl* shell = | 222 ShellImpl* shell = new ShellImpl(application.Pass(), this, requested_url, |
| 202 new ShellImpl(application.Pass(), this, requested_url, resolved_url); | 223 resolved_url, query_behavior); |
| 203 url_to_shell_impl_[resolved_url] = shell; | 224 url_to_shell_impl_[resolved_url] = shell; |
| 204 shell->InitializeApplication(GetArgsForURL(requested_url)); | 225 shell->InitializeApplication(GetArgsForURL(requested_url)); |
| 205 ConnectToClient(shell, resolved_url, requestor_url, services.Pass(), | 226 ConnectToClient(shell, requested_url, resolved_url, requestor_url, |
| 206 exposed_services.Pass()); | 227 services.Pass(), exposed_services.Pass()); |
| 207 return application_request.Pass(); | 228 return application_request.Pass(); |
| 208 } | 229 } |
| 209 | 230 |
| 210 ShellImpl* ApplicationManager::GetShellImpl(const GURL& url) { | 231 ShellImpl* ApplicationManager::GetShellImpl(const GURL& url) { |
| 211 const auto& shell_it = url_to_shell_impl_.find(url); | 232 const auto& shell_it = url_to_shell_impl_.find(url); |
| 212 if (shell_it != url_to_shell_impl_.end()) | 233 if (shell_it != url_to_shell_impl_.end()) |
| 213 return shell_it->second; | 234 return shell_it->second; |
| 214 return nullptr; | 235 return nullptr; |
| 215 } | 236 } |
| 216 | 237 |
| 217 void ApplicationManager::ConnectToClient( | 238 void ApplicationManager::ConnectToClient( |
| 218 ShellImpl* shell_impl, | 239 ShellImpl* shell_impl, |
| 219 const GURL& url, | 240 const GURL& requested_url, |
| 241 const GURL& resolved_url, // TODO(aa): Remove | |
|
qsr
2015/02/27 15:01:41
I think that it is requested_url that we can do wi
Aaron Boodman
2015/02/27 16:54:44
Done.
| |
| 220 const GURL& requestor_url, | 242 const GURL& requestor_url, |
| 221 InterfaceRequest<ServiceProvider> services, | 243 InterfaceRequest<ServiceProvider> services, |
| 222 ServiceProviderPtr exposed_services) { | 244 ServiceProviderPtr exposed_services) { |
| 223 shell_impl->ConnectToClient(requestor_url, services.Pass(), | 245 shell_impl->ConnectToClient(requested_url, requestor_url, services.Pass(), |
| 224 exposed_services.Pass()); | 246 exposed_services.Pass()); |
| 225 } | 247 } |
| 226 | 248 |
| 227 void ApplicationManager::HandleFetchCallback( | 249 void ApplicationManager::HandleFetchCallback( |
| 228 const GURL& requested_url, | 250 const GURL& requested_url, |
| 229 const GURL& requestor_url, | 251 const GURL& requestor_url, |
| 230 InterfaceRequest<ServiceProvider> services, | 252 InterfaceRequest<ServiceProvider> services, |
| 231 ServiceProviderPtr exposed_services, | 253 ServiceProviderPtr exposed_services, |
| 232 NativeRunner::CleanupBehavior cleanup_behavior, | 254 NativeRunner::CleanupBehavior cleanup_behavior, |
| 233 scoped_ptr<Fetcher> fetcher) { | 255 scoped_ptr<Fetcher> fetcher) { |
| 234 if (!fetcher) { | 256 if (!fetcher) { |
| 235 // Network error. Drop |application_request| to tell requestor. | 257 // Network error. Drop |application_request| to tell requestor. |
| 236 return; | 258 return; |
| 237 } | 259 } |
| 238 | 260 |
| 239 GURL redirect_url = fetcher->GetRedirectURL(); | 261 GURL redirect_url = fetcher->GetRedirectURL(); |
| 240 if (!redirect_url.is_empty()) { | 262 if (!redirect_url.is_empty()) { |
| 241 // And around we go again... Whee! | 263 // And around we go again... Whee! |
| 242 ConnectToApplication(redirect_url, requestor_url, services.Pass(), | 264 ConnectToApplication(redirect_url, requestor_url, services.Pass(), |
| 243 exposed_services.Pass()); | 265 exposed_services.Pass()); |
| 244 return; | 266 return; |
| 245 } | 267 } |
| 246 | 268 |
| 247 // We already checked if the application was running before we fetched it, but | 269 // We already checked if the application was running before we fetched it, but |
| 248 // it might have started while the fetch was outstanding. We don't want to | 270 // it might have started while the fetch was outstanding. We don't want to |
| 249 // have two copies of the app running, so check again. | 271 // have two copies of the app running, so check again. |
| 250 // | 272 // |
| 251 // Also, it's possible the original URL was redirected to an app that is | 273 // Also, it's possible the original URL was redirected to an app that is |
| 252 // already running. | 274 // already running. |
| 253 if (ConnectToRunningApplication(fetcher->GetURL(), requestor_url, &services, | 275 if (ConnectToRunningApplication(requested_url, fetcher->GetURL(), |
| 276 requestor_url, &services, | |
| 254 &exposed_services)) { | 277 &exposed_services)) { |
| 255 return; | 278 return; |
| 256 } | 279 } |
| 257 | 280 |
| 258 InterfaceRequest<Application> application_request( | |
| 259 RegisterShell(requested_url, fetcher->GetURL(), requestor_url, | |
| 260 services.Pass(), exposed_services.Pass())); | |
| 261 | |
| 262 // If the response begins with a #!mojo <content-handler-url>, use it. | 281 // If the response begins with a #!mojo <content-handler-url>, use it. |
| 263 GURL content_handler_url; | 282 GURL content_handler_url; |
| 264 std::string shebang; | 283 std::string shebang; |
| 265 if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) { | 284 if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) { |
| 266 LoadWithContentHandler( | 285 LoadWithContentHandler( |
| 267 content_handler_url, application_request.Pass(), | 286 content_handler_url, |
| 287 // #!mojo means this is a first-class mojo application, so it handles | |
| 288 // queries. | |
| 289 RegisterShell(requested_url, fetcher->GetURL(), requestor_url, | |
| 290 services.Pass(), exposed_services.Pass(), | |
| 291 ShellImpl::SHELL_HANDLES_QUERY), | |
| 268 fetcher->AsURLResponse(blocking_pool_, | 292 fetcher->AsURLResponse(blocking_pool_, |
| 269 static_cast<int>(shebang.size()))); | 293 static_cast<int>(shebang.size()))); |
| 270 return; | 294 return; |
| 271 } | 295 } |
| 272 | 296 |
| 273 MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(fetcher->MimeType()); | 297 MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(fetcher->MimeType()); |
| 274 if (iter != mime_type_to_url_.end()) { | 298 if (iter != mime_type_to_url_.end()) { |
| 275 LoadWithContentHandler(iter->second, application_request.Pass(), | 299 // Legacy content doesn't get automatic query handling. |
| 276 fetcher->AsURLResponse(blocking_pool_, 0)); | 300 LoadWithContentHandler( |
| 301 iter->second, | |
| 302 RegisterShell(requested_url, fetcher->GetURL(), requestor_url, | |
| 303 services.Pass(), exposed_services.Pass(), | |
| 304 ShellImpl::SHELL_DOES_NOT_HANDLE_QUERY), | |
| 305 fetcher->AsURLResponse(blocking_pool_, 0)); | |
| 277 return; | 306 return; |
| 278 } | 307 } |
| 279 | 308 |
| 280 // TODO(aa): Sanity check that the thing we got looks vaguely like a mojo | 309 // TODO(aa): Sanity check that the thing we got looks vaguely like a mojo |
| 281 // application. That could either mean looking for the platform-specific dll | 310 // application. That could either mean looking for the platform-specific dll |
| 282 // header, or looking for some specific mojo signature prepended to the | 311 // header, or looking for some specific mojo signature prepended to the |
| 283 // library. | 312 // library. |
| 284 | 313 |
| 285 fetcher->AsPath(blocking_pool_, | 314 fetcher->AsPath( |
| 286 base::Bind(&ApplicationManager::RunNativeApplication, | 315 blocking_pool_, |
| 287 weak_ptr_factory_.GetWeakPtr(), | 316 base::Bind( |
| 288 base::Passed(application_request.Pass()), | 317 &ApplicationManager::RunNativeApplication, |
| 289 cleanup_behavior, base::Passed(fetcher.Pass()))); | 318 weak_ptr_factory_.GetWeakPtr(), |
| 319 base::Passed(RegisterShell(requested_url, fetcher->GetURL(), | |
| 320 requestor_url, services.Pass(), | |
| 321 exposed_services.Pass(), | |
| 322 ShellImpl::SHELL_HANDLES_QUERY).Pass()), | |
| 323 cleanup_behavior, base::Passed(fetcher.Pass()))); | |
| 290 } | 324 } |
| 291 | 325 |
| 292 void ApplicationManager::RunNativeApplication( | 326 void ApplicationManager::RunNativeApplication( |
| 293 InterfaceRequest<Application> application_request, | 327 InterfaceRequest<Application> application_request, |
| 294 NativeRunner::CleanupBehavior cleanup_behavior, | 328 NativeRunner::CleanupBehavior cleanup_behavior, |
| 295 scoped_ptr<Fetcher> fetcher, | 329 scoped_ptr<Fetcher> fetcher, |
| 296 const base::FilePath& path, | 330 const base::FilePath& path, |
| 297 bool path_exists) { | 331 bool path_exists) { |
| 298 // We only passed fetcher to keep it alive. Done with it now. | 332 // We only passed fetcher to keep it alive. Done with it now. |
| 299 fetcher.reset(); | 333 fetcher.reset(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 315 | 349 |
| 316 void ApplicationManager::RegisterExternalApplication( | 350 void ApplicationManager::RegisterExternalApplication( |
| 317 const GURL& url, | 351 const GURL& url, |
| 318 const std::vector<std::string>& args, | 352 const std::vector<std::string>& args, |
| 319 ApplicationPtr application) { | 353 ApplicationPtr application) { |
| 320 const auto& args_it = url_to_args_.find(url); | 354 const auto& args_it = url_to_args_.find(url); |
| 321 if (args_it != url_to_args_.end()) { | 355 if (args_it != url_to_args_.end()) { |
| 322 LOG(WARNING) << "--args-for provided for external application " << url | 356 LOG(WARNING) << "--args-for provided for external application " << url |
| 323 << " <ignored>"; | 357 << " <ignored>"; |
| 324 } | 358 } |
| 325 ShellImpl* shell_impl = new ShellImpl(application.Pass(), this, url, url); | 359 ShellImpl* shell_impl = new ShellImpl(application.Pass(), this, url, url, |
| 360 ShellImpl::SHELL_DOES_NOT_HANDLE_QUERY); | |
| 326 url_to_shell_impl_[url] = shell_impl; | 361 url_to_shell_impl_[url] = shell_impl; |
| 327 shell_impl->InitializeApplication(Array<String>::From(args)); | 362 shell_impl->InitializeApplication(Array<String>::From(args)); |
| 328 } | 363 } |
| 329 | 364 |
| 330 void ApplicationManager::RegisterContentHandler( | 365 void ApplicationManager::RegisterContentHandler( |
| 331 const std::string& mime_type, | 366 const std::string& mime_type, |
| 332 const GURL& content_handler_url) { | 367 const GURL& content_handler_url) { |
| 333 DCHECK(content_handler_url.is_valid()) | 368 DCHECK(content_handler_url.is_valid()) |
| 334 << "Content handler URL is invalid for mime type " << mime_type; | 369 << "Content handler URL is invalid for mime type " << mime_type; |
| 335 mime_type_to_url_[mime_type] = content_handler_url; | 370 mime_type_to_url_[mime_type] = content_handler_url; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 return Array<String>::From(args_it->second); | 458 return Array<String>::From(args_it->second); |
| 424 return Array<String>(); | 459 return Array<String>(); |
| 425 } | 460 } |
| 426 | 461 |
| 427 void ApplicationManager::CleanupRunner(NativeRunner* runner) { | 462 void ApplicationManager::CleanupRunner(NativeRunner* runner) { |
| 428 native_runners_.erase( | 463 native_runners_.erase( |
| 429 std::find(native_runners_.begin(), native_runners_.end(), runner)); | 464 std::find(native_runners_.begin(), native_runners_.end(), runner)); |
| 430 } | 465 } |
| 431 | 466 |
| 432 } // namespace mojo | 467 } // namespace mojo |
| OLD | NEW |