diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 17:16:10 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 17:16:10 +0000 |
commit | e858750e720f24cd981b4222b025757d1f08bc3d (patch) | |
tree | d90277c6bc05882c563a61e2112b5da8125a97b3 /mojo | |
parent | bdab4937e356c11f6ab53c9bdce595354e812b2d (diff) | |
download | chromium_src-e858750e720f24cd981b4222b025757d1f08bc3d.zip chromium_src-e858750e720f24cd981b4222b025757d1f08bc3d.tar.gz chromium_src-e858750e720f24cd981b4222b025757d1f08bc3d.tar.bz2 |
Reland r288013: First cut at "content handling" support in Mojo.
TBR=darin@chromium.org
Review URL: https://codereview.chromium.org/456533002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288383 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
33 files changed, 705 insertions, 246 deletions
diff --git a/mojo/examples/content_handler_demo/content_handler_demo.cc b/mojo/examples/content_handler_demo/content_handler_demo.cc new file mode 100644 index 0000000..21864f7 --- /dev/null +++ b/mojo/examples/content_handler_demo/content_handler_demo.cc @@ -0,0 +1,89 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdio.h> + +#include "mojo/public/cpp/application/application_delegate.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/application/interface_factory_impl.h" +#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h" + +namespace mojo { +namespace examples { + +class ContentHandlerApp; + +class ContentHandlerImpl : public InterfaceImpl<ContentHandler> { + public: + explicit ContentHandlerImpl(ContentHandlerApp* content_handler_app) + : content_handler_app_(content_handler_app) { + } + virtual ~ContentHandlerImpl() {} + + private: + virtual void OnConnect(const mojo::String& url, + URLResponsePtr content, + ServiceProviderPtr service_provider) MOJO_OVERRIDE; + + ContentHandlerApp* content_handler_app_; +}; + +class ContentHandlerApp : public ApplicationDelegate { + public: + ContentHandlerApp() : content_handler_factory_(this) { + } + + virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE { + } + + virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) + MOJO_OVERRIDE { + connection->AddService(&content_handler_factory_); + return true; + } + + void PrintResponse(ScopedDataPipeConsumerHandle body) const { + for (;;) { + char buf[512]; + uint32_t num_bytes = sizeof(buf); + MojoResult result = ReadDataRaw(body.get(), buf, &num_bytes, + MOJO_READ_DATA_FLAG_NONE); + if (result == MOJO_RESULT_SHOULD_WAIT) { + Wait(body.get(), + MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE); + } else if (result == MOJO_RESULT_OK) { + if (fwrite(buf, num_bytes, 1, stdout) != 1) { + printf("\nUnexpected error writing to file\n"); + break; + } + } else { + break; + } + + printf("\n>>> EOF <<<\n"); + } + } + + private: + InterfaceFactoryImplWithContext<ContentHandlerImpl, + ContentHandlerApp> content_handler_factory_; +}; + +void ContentHandlerImpl::OnConnect(const mojo::String& url, + URLResponsePtr content, + ServiceProviderPtr service_provider) { + printf("ContentHandler::OnConnect - url:%s - body follows\n\n", + url.To<std::string>().c_str()); + content_handler_app_->PrintResponse(content->body.Pass()); +} + +} // namespace examples + +// static +ApplicationDelegate* ApplicationDelegate::Create() { + return new examples::ContentHandlerApp(); +} + +} // namespace mojo diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index ecea8dee..810edd2 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -27,6 +27,7 @@ 'mojo_base.gyp:mojo_base', 'mojo_apps_js_unittests', 'mojo_compositor_app', + 'mojo_content_handler_demo', 'mojo_echo_client', 'mojo_echo_service', 'mojo_example_apptests', @@ -341,6 +342,8 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../net/net.gyp:net', '../url/url.gyp:url_lib', + 'mojo_content_handler_bindings', + 'mojo_network_bindings', 'mojo_base.gyp:mojo_application_bindings', 'mojo_base.gyp:mojo_common_lib', 'mojo_base.gyp:mojo_environment_chromium', @@ -349,6 +352,7 @@ 'sources': [ 'service_manager/background_shell_service_loader.cc', 'service_manager/background_shell_service_loader.h', + 'service_manager/service_loader.cc', 'service_manager/service_loader.h', 'service_manager/service_manager.cc', 'service_manager/service_manager.h', diff --git a/mojo/mojo_examples.gypi b/mojo/mojo_examples.gypi index 836305c..287901e 100644 --- a/mojo/mojo_examples.gypi +++ b/mojo/mojo_examples.gypi @@ -205,6 +205,22 @@ ], }, { + 'target_name': 'mojo_content_handler_demo', + 'type': 'loadable_module', + 'dependencies': [ + 'mojo_base.gyp:mojo_application_standalone', + 'mojo_base.gyp:mojo_cpp_bindings', + 'mojo_base.gyp:mojo_environment_standalone', + 'mojo_base.gyp:mojo_utility', + 'mojo_content_handler_bindings', + '<(mojo_system_for_loadable_module)', + ], + 'sources': [ + 'examples/content_handler_demo/content_handler_demo.cc', + 'public/cpp/application/lib/mojo_main_standalone.cc', + ], + }, + { 'target_name': 'package_mojo_wget', 'variables': { 'app_name': 'mojo_wget', diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index 3e07f8e..611aee0 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -365,6 +365,23 @@ ], }, { + # GN version: //mojo/services/public/interfaces/content_handler + 'target_name': 'mojo_content_handler_bindings', + 'type': 'static_library', + 'sources': [ + 'services/public/interfaces/content_handler/content_handler.mojom', + ], + 'includes': [ 'public/tools/bindings/mojom_bindings_generator.gypi' ], + 'export_dependent_settings': [ + 'mojo_base.gyp:mojo_cpp_bindings', + ], + 'dependencies': [ + 'mojo_base.gyp:mojo_application_bindings', + 'mojo_base.gyp:mojo_cpp_bindings', + 'mojo_network_bindings', + ], + }, + { # GN version: //mojo/services/public/interfaces/network 'target_name': 'mojo_network_bindings', 'type': 'static_library', diff --git a/mojo/service_manager/BUILD.gn b/mojo/service_manager/BUILD.gn index c526e6d..c7d8790 100644 --- a/mojo/service_manager/BUILD.gn +++ b/mojo/service_manager/BUILD.gn @@ -8,6 +8,7 @@ component("service_manager") { sources = [ "background_shell_service_loader.cc", "background_shell_service_loader.h", + "service_loader.cc", "service_loader.h", "service_manager.cc", "service_manager.h", @@ -24,6 +25,8 @@ component("service_manager") { "//mojo/common", "//mojo/environment:chromium", "//mojo/public/interfaces/application:application", + "//mojo/services/public/interfaces/content_handler:content_handler", + "//mojo/services/public/interfaces/network:network", "//mojo/system", ] diff --git a/mojo/service_manager/background_shell_service_loader.cc b/mojo/service_manager/background_shell_service_loader.cc index ef97255..d0e5e97 100644 --- a/mojo/service_manager/background_shell_service_loader.cc +++ b/mojo/service_manager/background_shell_service_loader.cc @@ -15,10 +15,12 @@ class BackgroundShellServiceLoader::BackgroundLoader { explicit BackgroundLoader(ServiceLoader* loader) : loader_(loader) {} ~BackgroundLoader() {} - void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { - loader_->LoadService(manager, url, shell_handle.Pass()); + void Load(ServiceManager* manager, + const GURL& url, + ScopedMessagePipeHandle shell_handle) { + scoped_refptr<LoadCallbacks> callbacks( + new ServiceLoader::SimpleLoadCallbacks(shell_handle.Pass())); + loader_->Load(manager, url, callbacks); } void OnServiceError(ServiceManager* manager, const GURL& url) { @@ -47,17 +49,21 @@ BackgroundShellServiceLoader::~BackgroundShellServiceLoader() { thread_->Join(); } -void BackgroundShellServiceLoader::LoadService( +void BackgroundShellServiceLoader::Load( ServiceManager* manager, const GURL& url, - ScopedMessagePipeHandle shell_handle) { + scoped_refptr<LoadCallbacks> callbacks) { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; + if (!thread_) { - // TODO(tim): It'd be nice if we could just have each LoadService call + // TODO(tim): It'd be nice if we could just have each Load call // result in a new thread like DynamicService{Loader, Runner}. But some // loaders are creating multiple ApplicationImpls (NetworkServiceLoader) // sharing a delegate (etc). So we have to keep it single threaded, wait // for the thread to initialize, and post to the TaskRunner for subsequent - // LoadService calls for now. + // Load calls for now. thread_.reset(new base::DelegateSimpleThread(this, thread_name_)); thread_->Start(); message_loop_created_.Wait(); @@ -65,7 +71,7 @@ void BackgroundShellServiceLoader::LoadService( } task_runner_->PostTask(FROM_HERE, - base::Bind(&BackgroundShellServiceLoader::LoadServiceOnBackgroundThread, + base::Bind(&BackgroundShellServiceLoader::LoadOnBackgroundThread, base::Unretained(this), manager, url, base::Owned( new ScopedMessagePipeHandle(shell_handle.Pass())))); @@ -93,14 +99,14 @@ void BackgroundShellServiceLoader::Run() { loader_.reset(); } -void BackgroundShellServiceLoader::LoadServiceOnBackgroundThread( +void BackgroundShellServiceLoader::LoadOnBackgroundThread( ServiceManager* manager, const GURL& url, ScopedMessagePipeHandle* shell_handle) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); if (!background_loader_) background_loader_ = new BackgroundLoader(loader_.get()); - background_loader_->LoadService(manager, url, shell_handle->Pass()); + background_loader_->Load(manager, url, shell_handle->Pass()); } void BackgroundShellServiceLoader::OnServiceErrorOnBackgroundThread( diff --git a/mojo/service_manager/background_shell_service_loader.h b/mojo/service_manager/background_shell_service_loader.h index 3f4b3fc..a28b33f 100644 --- a/mojo/service_manager/background_shell_service_loader.h +++ b/mojo/service_manager/background_shell_service_loader.h @@ -26,9 +26,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader : virtual ~BackgroundShellServiceLoader(); // ServiceLoader overrides: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; @@ -42,10 +42,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader : // to |background_loader_| to do the actual loading. // TODO: having this code take a |manager| is fragile (as ServiceManager isn't // thread safe). - void LoadServiceOnBackgroundThread( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle* shell_handle); + void LoadOnBackgroundThread(ServiceManager* manager, + const GURL& url, + ScopedMessagePipeHandle* shell_handle); void OnServiceErrorOnBackgroundThread(ServiceManager* manager, const GURL& url); bool quit_on_shutdown_; diff --git a/mojo/service_manager/background_shell_service_loader_unittest.cc b/mojo/service_manager/background_shell_service_loader_unittest.cc index 7469b0f..8aeacba 100644 --- a/mojo/service_manager/background_shell_service_loader_unittest.cc +++ b/mojo/service_manager/background_shell_service_loader_unittest.cc @@ -16,9 +16,9 @@ class DummyLoader : public ServiceLoader { virtual ~DummyLoader() {} // ServiceLoader overrides: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE { + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { if (simulate_app_quit_) base::MessageLoop::current()->Quit(); } @@ -49,7 +49,9 @@ TEST(BackgroundShellServiceLoaderTest, Load) { BackgroundShellServiceLoader loader(real_loader.Pass(), "test", base::MessageLoop::TYPE_DEFAULT); MessagePipe dummy; - loader.LoadService(NULL, GURL(), dummy.handle0.Pass()); + scoped_refptr<ServiceLoader::SimpleLoadCallbacks> callbacks( + new ServiceLoader::SimpleLoadCallbacks(dummy.handle0.Pass())); + loader.Load(NULL, GURL(), callbacks); } } // namespace mojo diff --git a/mojo/service_manager/service_loader.cc b/mojo/service_manager/service_loader.cc new file mode 100644 index 0000000..01c6803 --- /dev/null +++ b/mojo/service_manager/service_loader.cc @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/service_manager/service_loader.h" + +#include "base/logging.h" + +namespace mojo { + +ServiceLoader::SimpleLoadCallbacks::SimpleLoadCallbacks( + ScopedMessagePipeHandle shell_handle) + : shell_handle_(shell_handle.Pass()) { +} + +ServiceLoader::SimpleLoadCallbacks::~SimpleLoadCallbacks() { +} + +ScopedMessagePipeHandle +ServiceLoader::SimpleLoadCallbacks::RegisterApplication() { + return shell_handle_.Pass(); +} + +void ServiceLoader::SimpleLoadCallbacks::LoadWithContentHandler( + const GURL& content_handle_url, URLResponsePtr content) { + NOTREACHED(); +} + +} // namespace mojo diff --git a/mojo/service_manager/service_loader.h b/mojo/service_manager/service_loader.h index 07be7d9..5c44a53 100644 --- a/mojo/service_manager/service_loader.h +++ b/mojo/service_manager/service_loader.h @@ -5,8 +5,10 @@ #ifndef MOJO_SERVICE_MANAGER_SERVICE_LOADER_H_ #define MOJO_SERVICE_MANAGER_SERVICE_LOADER_H_ +#include "base/memory/ref_counted.h" #include "mojo/public/cpp/system/core.h" #include "mojo/service_manager/service_manager_export.h" +#include "mojo/services/public/interfaces/network/url_loader.mojom.h" #include "url/gurl.h" namespace mojo { @@ -23,10 +25,54 @@ class ServiceManager; // apps and services. class MOJO_SERVICE_MANAGER_EXPORT ServiceLoader { public: + class MOJO_SERVICE_MANAGER_EXPORT LoadCallbacks + : public base::RefCounted<LoadCallbacks> { + public: + // Register the requested application with ServiceManager. If the returned + // handle is valid, it should be used to implement the mojo::Application + // interface. + virtual ScopedMessagePipeHandle RegisterApplication() = 0; + + // Load the requested application with a content handler. + virtual void LoadWithContentHandler(const GURL& content_handler_url, + URLResponsePtr response) = 0; + protected: + friend base::RefCounted<LoadCallbacks>; + virtual ~LoadCallbacks() {} + }; + + // Implements RegisterApplication() by returning a handle that was specified + // at construction time. LoadWithContentHandler() is not supported. + class MOJO_SERVICE_MANAGER_EXPORT SimpleLoadCallbacks : public LoadCallbacks { + public: + SimpleLoadCallbacks(ScopedMessagePipeHandle shell_handle); + virtual ScopedMessagePipeHandle RegisterApplication() OVERRIDE; + virtual void LoadWithContentHandler(const GURL& content_handler_url, + URLResponsePtr response) OVERRIDE; + private: + ScopedMessagePipeHandle shell_handle_; + virtual ~SimpleLoadCallbacks(); + }; + virtual ~ServiceLoader() {} - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) = 0; + + // Load the application named |url|. Applications can be loaded two ways: + // + // 1. |url| can refer directly to a Mojo application. In this case, call + // callbacks->RegisterApplication(). The returned handle should be used to + // implement the mojo.Application interface. Note that the returned handle + // can be invalid in the case where the application has already been + // loaded. + // + // 2. |url| can refer to some content that can be handled by some other Mojo + // application. In this case, call callbacks->LoadWithContentHandler() and + // specify the URL of the application that should handle the content. + // The specified application must implement the mojo.ContentHandler + // interface. + virtual void Load(ServiceManager* service_manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) = 0; + virtual void OnServiceError(ServiceManager* manager, const GURL& url) = 0; protected: diff --git a/mojo/service_manager/service_manager.cc b/mojo/service_manager/service_manager.cc index 51efd41..b0ef1e8 100644 --- a/mojo/service_manager/service_manager.cc +++ b/mojo/service_manager/service_manager.cc @@ -2,18 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <stdio.h> - #include "mojo/service_manager/service_manager.h" +#include <stdio.h> + +#include "base/bind.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" #include "base/stl_util.h" #include "mojo/common/common_type_converters.h" +#include "mojo/public/cpp/application/connect.h" #include "mojo/public/interfaces/application/application.mojom.h" #include "mojo/public/interfaces/application/shell.mojom.h" #include "mojo/service_manager/service_loader.h" +#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h" namespace mojo { @@ -33,7 +36,52 @@ class StubServiceProvider : public InterfaceImpl<ServiceProvider> { ScopedMessagePipeHandle client_handle) MOJO_OVERRIDE {} }; -} +} // namespace + +class ServiceManager::LoadCallbacksImpl : public ServiceLoader::LoadCallbacks { + public: + LoadCallbacksImpl(base::WeakPtr<ServiceManager> manager, + const GURL& requested_url, + const GURL& requestor_url, + ServiceProviderPtr service_provider) + : manager_(manager), + requested_url_(requested_url), + requestor_url_(requestor_url), + service_provider_(service_provider.Pass()) { + } + + private: + virtual ~LoadCallbacksImpl() { + } + + // LoadCallbacks implementation + virtual ScopedMessagePipeHandle RegisterApplication() OVERRIDE { + ScopedMessagePipeHandle shell_handle; + if (manager_) { + manager_->RegisterLoadedApplication(requested_url_, + requestor_url_, + service_provider_.Pass(), + &shell_handle); + } + return shell_handle.Pass(); + } + + virtual void LoadWithContentHandler(const GURL& content_handler_url, + URLResponsePtr content) OVERRIDE { + if (manager_) { + manager_->LoadWithContentHandler(requested_url_, + requestor_url_, + content_handler_url, + content.Pass(), + service_provider_.Pass()); + } + } + + base::WeakPtr<ServiceManager> manager_; + GURL requested_url_; + GURL requestor_url_; + ServiceProviderPtr service_provider_; +}; class ServiceManager::ShellImpl : public InterfaceImpl<Shell> { public: @@ -76,6 +124,21 @@ class ServiceManager::ShellImpl : public InterfaceImpl<Shell> { DISALLOW_COPY_AND_ASSIGN(ShellImpl); }; +struct ServiceManager::ContentHandlerConnection { + ContentHandlerConnection(ServiceManager* manager, + const GURL& content_handler_url) { + ServiceProviderPtr service_provider; + BindToProxy(&service_provider_impl, &service_provider); + manager->ConnectToApplication(content_handler_url, + GURL(), + service_provider.Pass()); + mojo::ConnectToService(service_provider_impl.client(), &content_handler); + } + + StubServiceProvider service_provider_impl; + ContentHandlerPtr content_handler; +}; + // static ServiceManager::TestAPI::TestAPI(ServiceManager* manager) : manager_(manager) { } @@ -92,10 +155,13 @@ bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const { manager_->url_to_shell_impl_.end(); } -ServiceManager::ServiceManager() : interceptor_(NULL) { +ServiceManager::ServiceManager() + : interceptor_(NULL), + weak_ptr_factory_(this) { } ServiceManager::~ServiceManager() { + STLDeleteValues(&url_to_content_handler_); TerminateShellConnections(); STLDeleteValues(&url_to_loader_); STLDeleteValues(&scheme_to_loader_); @@ -117,15 +183,24 @@ void ServiceManager::ConnectToApplication(const GURL& url, const GURL& requestor_url, ServiceProviderPtr service_provider) { URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url); - ShellImpl* shell_impl; if (shell_it != url_to_shell_impl_.end()) { - shell_impl = shell_it->second; - } else { - MessagePipe pipe; - GetLoaderForURL(url)->LoadService(this, url, pipe.handle0.Pass()); - shell_impl = WeakBindToPipe(new ShellImpl(this, url), pipe.handle1.Pass()); - url_to_shell_impl_[url] = shell_impl; + ConnectToClient(shell_it->second, url, requestor_url, + service_provider.Pass()); + return; } + + scoped_refptr<LoadCallbacksImpl> callbacks( + new LoadCallbacksImpl(weak_ptr_factory_.GetWeakPtr(), + url, + requestor_url, + service_provider.Pass())); + GetLoaderForURL(url)->Load(this, url, callbacks); +} + +void ServiceManager::ConnectToClient(ShellImpl* shell_impl, + const GURL& url, + const GURL& requestor_url, + ServiceProviderPtr service_provider) { if (interceptor_) { shell_impl->ConnectToClient( requestor_url, @@ -135,6 +210,48 @@ void ServiceManager::ConnectToApplication(const GURL& url, } } +void ServiceManager::RegisterLoadedApplication( + const GURL& url, + const GURL& requestor_url, + ServiceProviderPtr service_provider, + ScopedMessagePipeHandle* shell_handle) { + ShellImpl* shell_impl = NULL; + URLToShellImplMap::iterator iter = url_to_shell_impl_.find(url); + if (iter != url_to_shell_impl_.end()) { + // This can happen because services are loaded asynchronously. So if we get + // two requests for the same service close to each other, we might get here + // and find that we already have it. + shell_impl = iter->second; + } else { + MessagePipe pipe; + shell_impl = WeakBindToPipe(new ShellImpl(this, url), pipe.handle1.Pass()); + url_to_shell_impl_[url] = shell_impl; + *shell_handle = pipe.handle0.Pass(); + } + + ConnectToClient(shell_impl, url, requestor_url, service_provider.Pass()); +} + +void ServiceManager::LoadWithContentHandler( + const GURL& content_url, + const GURL& requestor_url, + const GURL& content_handler_url, + URLResponsePtr content, + ServiceProviderPtr service_provider) { + ContentHandlerConnection* connection = NULL; + URLToContentHandlerMap::iterator iter = + url_to_content_handler_.find(content_handler_url); + if (iter != url_to_content_handler_.end()) { + connection = iter->second; + } else { + connection = new ContentHandlerConnection(this, content_handler_url); + url_to_content_handler_[content_handler_url] = connection; + } + connection->content_handler->OnConnect(content_url.spec(), + content.Pass(), + service_provider.Pass()); +} + void ServiceManager::SetLoaderForURL(scoped_ptr<ServiceLoader> loader, const GURL& url) { URLToLoaderMap::iterator it = url_to_loader_.find(url); diff --git a/mojo/service_manager/service_manager.h b/mojo/service_manager/service_manager.h index 69ebda6..76cda8c 100644 --- a/mojo/service_manager/service_manager.h +++ b/mojo/service_manager/service_manager.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "mojo/public/interfaces/application/service_provider.mojom.h" #include "mojo/service_manager/service_loader.h" #include "mojo/service_manager/service_manager_export.h" @@ -87,10 +88,30 @@ class MOJO_SERVICE_MANAGER_EXPORT ServiceManager { void TerminateShellConnections(); private: + struct ContentHandlerConnection; + class LoadCallbacksImpl; class ShellImpl; + typedef std::map<std::string, ServiceLoader*> SchemeToLoaderMap; typedef std::map<GURL, ServiceLoader*> URLToLoaderMap; typedef std::map<GURL, ShellImpl*> URLToShellImplMap; + typedef std::map<GURL, ContentHandlerConnection*> URLToContentHandlerMap; + + void ConnectToClient(ShellImpl* shell_impl, + const GURL& url, + const GURL& requestor_url, + ServiceProviderPtr service_provider); + + void RegisterLoadedApplication(const GURL& service_url, + const GURL& requestor_url, + ServiceProviderPtr service_provider, + ScopedMessagePipeHandle* shell_handle); + + void LoadWithContentHandler(const GURL& content_url, + const GURL& requestor_url, + const GURL& content_handler_url, + URLResponsePtr content, + ServiceProviderPtr service_provider); // Returns the Loader to use for a url (using default if not overridden.) // The preference is to use a loader that's been specified for an url first, @@ -107,6 +128,9 @@ class MOJO_SERVICE_MANAGER_EXPORT ServiceManager { Interceptor* interceptor_; URLToShellImplMap url_to_shell_impl_; + URLToContentHandlerMap url_to_content_handler_; + + base::WeakPtrFactory<ServiceManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ServiceManager); }; diff --git a/mojo/service_manager/service_manager_unittest.cc b/mojo/service_manager/service_manager_unittest.cc index f42113f..0f984c17 100644 --- a/mojo/service_manager/service_manager_unittest.cc +++ b/mojo/service_manager/service_manager_unittest.cc @@ -118,12 +118,12 @@ class TestServiceLoader : public ServiceLoader, private: // ServiceLoader implementation. - virtual void LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle service_provider_handle) OVERRIDE { + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { ++num_loads_; - test_app_.reset(new ApplicationImpl(this, service_provider_handle.Pass())); + test_app_.reset( + new ApplicationImpl(this, callbacks->RegisterApplication().Pass())); } virtual void OnServiceError(ServiceManager* manager, @@ -332,11 +332,11 @@ class Tester : public ApplicationDelegate, virtual ~Tester() {} private: - virtual void LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE { - app_.reset(new ApplicationImpl(this, shell_handle.Pass())); + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { + app_.reset( + new ApplicationImpl(this, callbacks->RegisterApplication().Pass())); } virtual void OnServiceError(ServiceManager* manager, diff --git a/mojo/services/BUILD.gn b/mojo/services/BUILD.gn index 09753e07..619a9f9 100644 --- a/mojo/services/BUILD.gn +++ b/mojo/services/BUILD.gn @@ -6,6 +6,7 @@ group("services") { deps = [ "//mojo/services/dbus_echo:bindings", "//mojo/services/gles2:bindings", + "//mojo/services/public/interfaces/content_handler", "//mojo/services/public/interfaces/input_events", "//mojo/services/public/interfaces/geometry", "//mojo/services/public/interfaces/native_viewport", diff --git a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc index f56a060..7afde90 100644 --- a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc +++ b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc @@ -55,9 +55,12 @@ class ConnectServiceLoader : public ServiceLoader, private: // Overridden from ServiceLoader: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE { + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this, shell_handle.Pass())); apps_.push_back(app.release()); diff --git a/mojo/services/public/interfaces/content_handler/BUILD.gn b/mojo/services/public/interfaces/content_handler/BUILD.gn new file mode 100644 index 0000000..c72cc9a --- /dev/null +++ b/mojo/services/public/interfaces/content_handler/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +# GYP version: mojo/mojo_services.gypi:mojo_content_handler_bindings +mojom("content_handler") { + sources = [ + "content_handler.mojom", + ] + + deps = [ + "//mojo/public/interfaces/application", + "//mojo/services/public/interfaces/network", + ] +} diff --git a/mojo/services/public/interfaces/content_handler/content_handler.mojom b/mojo/services/public/interfaces/content_handler/content_handler.mojom new file mode 100644 index 0000000..6c07580 --- /dev/null +++ b/mojo/services/public/interfaces/content_handler/content_handler.mojom @@ -0,0 +1,16 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import "mojo/public/interfaces/application/service_provider.mojom" +import "mojo/services/public/interfaces/network/url_loader.mojom" + +module mojo { + +interface ContentHandler { + OnConnect(string url, + URLResponse url_response, + ServiceProvider service_provider); +}; + +} diff --git a/mojo/services/view_manager/view_manager_unittest.cc b/mojo/services/view_manager/view_manager_unittest.cc index 3d24a18..8c3e13f 100644 --- a/mojo/services/view_manager/view_manager_unittest.cc +++ b/mojo/services/view_manager/view_manager_unittest.cc @@ -386,9 +386,12 @@ class EmbedServiceLoader : public ServiceLoader, virtual ~EmbedServiceLoader() {} // ServiceLoader implementation: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE { + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this, shell_handle.Pass())); apps_.push_back(app.release()); diff --git a/mojo/services/window_manager/window_manager_api_unittest.cc b/mojo/services/window_manager/window_manager_api_unittest.cc index 4450c3b..b557bc9 100644 --- a/mojo/services/window_manager/window_manager_api_unittest.cc +++ b/mojo/services/window_manager/window_manager_api_unittest.cc @@ -132,9 +132,12 @@ class TestServiceLoader : public ServiceLoader, private: // Overridden from ServiceLoader: - virtual void LoadService(ServiceManager* service_manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) MOJO_OVERRIDE { + virtual void Load(ServiceManager* service_manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) MOJO_OVERRIDE { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; scoped_ptr<ApplicationImpl> app( new ApplicationImpl(this, shell_handle.Pass())); apps_.push_back(app.release()); diff --git a/mojo/shell/context.cc b/mojo/shell/context.cc index 76cc7d6..a6dea44 100644 --- a/mojo/shell/context.cc +++ b/mojo/shell/context.cc @@ -4,10 +4,13 @@ #include "mojo/shell/context.h" +#include <vector> + #include "build/build_config.h" #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/memory/scoped_vector.h" +#include "base/strings/string_split.h" #include "mojo/embedder/embedder.h" #include "mojo/gles2/gles2_support_impl.h" #include "mojo/public/cpp/application/application_impl.h" @@ -61,6 +64,32 @@ class Setup { static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER; +void InitContentHandlers(DynamicServiceLoader* loader, + base::CommandLine* command_line) { + std::string handlers_spec = command_line->GetSwitchValueASCII( + switches::kContentHandlers); + if (handlers_spec.empty()) + return; + + std::vector<std::string> parts; + base::SplitString(handlers_spec, ',', &parts); + if (parts.size() % 2 != 0) { + LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers + << ": must be a comma-separated list of mimetype/url pairs."; + return; + } + + for (size_t i = 0; i < parts.size(); i += 2) { + GURL url(parts[i + 1]); + if (!url.is_valid()) { + LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers + << ": '" << parts[i + 1] << "' is not a valid URL."; + return; + } + loader->RegisterContentHandler(parts[i], url); + } +} + } // namespace class Context::NativeViewportServiceLoader : public ServiceLoader { @@ -69,10 +98,12 @@ class Context::NativeViewportServiceLoader : public ServiceLoader { virtual ~NativeViewportServiceLoader() {} private: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE { - app_.reset(services::CreateNativeViewportService(shell_handle.Pass())); + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (shell_handle.is_valid()) + app_.reset(services::CreateNativeViewportService(shell_handle.Pass())); } virtual void OnServiceError(ServiceManager* manager, @@ -95,16 +126,19 @@ void Context::Init() { for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i) mojo_url_resolver_.AddLocalFileMapping(GURL(kLocalMojoURLs[i])); - base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); scoped_ptr<DynamicServiceRunnerFactory> runner_factory; - if (cmdline->HasSwitch(switches::kEnableMultiprocess)) + if (command_line->HasSwitch(switches::kEnableMultiprocess)) runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory()); else runner_factory.reset(new InProcessDynamicServiceRunnerFactory()); + DynamicServiceLoader* dynamic_service_loader = + new DynamicServiceLoader(this, runner_factory.Pass()); + InitContentHandlers(dynamic_service_loader, command_line); service_manager_.set_default_loader( - scoped_ptr<ServiceLoader>( - new DynamicServiceLoader(this, runner_factory.Pass()))); + scoped_ptr<ServiceLoader>(dynamic_service_loader)); + // The native viewport service synchronously waits for certain messages. If we // don't run it on its own thread we can easily deadlock. Long term native // viewport should run its own process so that this isn't an issue. @@ -140,9 +174,9 @@ void Context::Init() { "dbus"); #endif // defined(OS_LINUX) - if (cmdline->HasSwitch(switches::kSpy)) { - spy_.reset(new mojo::Spy(&service_manager_, - cmdline->GetSwitchValueASCII(switches::kSpy))); + if (command_line->HasSwitch(switches::kSpy)) { + spy_.reset(new mojo::Spy( + &service_manager_, command_line->GetSwitchValueASCII(switches::kSpy))); } #if defined(OS_ANDROID) diff --git a/mojo/shell/dbus_service_loader_linux.cc b/mojo/shell/dbus_service_loader_linux.cc index af4e0d4..934637e 100644 --- a/mojo/shell/dbus_service_loader_linux.cc +++ b/mojo/shell/dbus_service_loader_linux.cc @@ -150,9 +150,15 @@ DBusServiceLoader::~DBusServiceLoader() { DCHECK(url_to_load_context_.empty()); } -void DBusServiceLoader::LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { +void DBusServiceLoader::Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) { + // TODO(aa): This could be delayed until later, when we know that loading is + // going to succeed. + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; + DCHECK(url.SchemeIs("dbus")); DCHECK(url_to_load_context_.find(url) == url_to_load_context_.end()); url_to_load_context_[url] = diff --git a/mojo/shell/dbus_service_loader_linux.h b/mojo/shell/dbus_service_loader_linux.h index a24af5f..1aae927 100644 --- a/mojo/shell/dbus_service_loader_linux.h +++ b/mojo/shell/dbus_service_loader_linux.h @@ -61,9 +61,9 @@ class DBusServiceLoader : public ServiceLoader { // the name "org.chromium.EchoService" and invoke the method // "org.chromium.Mojo.ConnectChannel" on the object exported at // "/org/chromium/MojoImpl". - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; diff --git a/mojo/shell/dynamic_service_loader.cc b/mojo/shell/dynamic_service_loader.cc index a8e6914..73dd6dd 100644 --- a/mojo/shell/dynamic_service_loader.cc +++ b/mojo/shell/dynamic_service_loader.cc @@ -20,122 +20,15 @@ namespace mojo { namespace shell { -namespace { - -class Loader { - public: - explicit Loader(scoped_ptr<DynamicServiceRunner> runner) - : runner_(runner.Pass()) { - } - - virtual void Start(const GURL& url, - ScopedMessagePipeHandle service_handle, - Context* context) = 0; - - void StartService(const base::FilePath& path, - ScopedMessagePipeHandle service_handle, - bool path_is_valid) { - if (path_is_valid) { - runner_->Start(path, service_handle.Pass(), - base::Bind(&Loader::AppCompleted, base::Unretained(this))); - } else { - AppCompleted(); - } - } - - protected: - virtual ~Loader() {} - - private: - void AppCompleted() { - delete this; - } - - scoped_ptr<DynamicServiceRunner> runner_; -}; - -// For loading services via file:// URLs. -class LocalLoader : public Loader { - public: - explicit LocalLoader(scoped_ptr<DynamicServiceRunner> runner) - : Loader(runner.Pass()) { - } - - virtual void Start(const GURL& url, - ScopedMessagePipeHandle service_handle, - Context* context) OVERRIDE { - base::FilePath path; - net::FileURLToFilePath(url, &path); - - // Complete asynchronously for consistency with NetworkServiceLoader. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&Loader::StartService, - base::Unretained(this), - path, - base::Passed(&service_handle), - base::PathExists(path))); - } -}; - -// For loading services via the network stack. -class NetworkLoader : public Loader { - public: - explicit NetworkLoader(scoped_ptr<DynamicServiceRunner> runner, - NetworkService* network_service) - : Loader(runner.Pass()) { - network_service->CreateURLLoader(Get(&url_loader_)); - } - - virtual void Start(const GURL& url, - ScopedMessagePipeHandle service_handle, - Context* context) OVERRIDE { - service_handle_ = service_handle.Pass(); - context_ = context; - - URLRequestPtr request(URLRequest::New()); - request->url = String::From(url); - request->auto_follow_redirects = true; - - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableCache)) { - request->bypass_cache = true; - } - - url_loader_->Start(request.Pass(), - base::Bind(&NetworkLoader::OnReceivedResponse, - base::Unretained(this))); - } - - private: - virtual ~NetworkLoader() { - if (!file_.empty()) - base::DeleteFile(file_, false); - } - void OnReceivedResponse(URLResponsePtr response) { - if (response->error) { - LOG(ERROR) << "Error (" << response->error->code << ": " - << response->error->description << ") while fetching " - << response->url; - } - - base::CreateTemporaryFile(&file_); - common::CopyToFile(response->body.Pass(), - file_, - context_->task_runners()->blocking_pool(), - base::Bind(&Loader::StartService, - base::Unretained(this), - file_, - base::Passed(&service_handle_))); - } +namespace { - Context* context_; - NetworkServicePtr network_service_; - URLLoaderPtr url_loader_; - ScopedMessagePipeHandle service_handle_; - base::FilePath file_; -}; +void RunLibraryComplete(DynamicServiceRunner* runner, + const base::FilePath& temp_file) { + delete runner; + if (!temp_file.empty()) + base::DeleteFile(temp_file, false); +} } // namespace @@ -143,17 +36,22 @@ DynamicServiceLoader::DynamicServiceLoader( Context* context, scoped_ptr<DynamicServiceRunnerFactory> runner_factory) : context_(context), - runner_factory_(runner_factory.Pass()) { + runner_factory_(runner_factory.Pass()), + weak_ptr_factory_(this) { } DynamicServiceLoader::~DynamicServiceLoader() { } -void DynamicServiceLoader::LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { - scoped_ptr<DynamicServiceRunner> runner = runner_factory_->Create(context_); +void DynamicServiceLoader::RegisterContentHandler( + const std::string& mime_type, + const GURL& content_handler_url) { + mime_type_to_url_[mime_type] = content_handler_url; +} +void DynamicServiceLoader::Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) { GURL resolved_url; if (url.SchemeIs("mojo")) { resolved_url = context_->mojo_url_resolver()->Resolve(url); @@ -161,18 +59,109 @@ void DynamicServiceLoader::LoadService(ServiceManager* manager, resolved_url = url; } - Loader* loader; - if (resolved_url.SchemeIsFile()) { - loader = new LocalLoader(runner.Pass()); - } else { - if (!network_service_) { - context_->service_manager()->ConnectToService( - GURL("mojo:mojo_network_service"), - &network_service_); - } - loader = new NetworkLoader(runner.Pass(), network_service_.get()); + if (resolved_url.SchemeIsFile()) + LoadLocalService(resolved_url, callbacks); + else + LoadNetworkService(resolved_url, callbacks); +} + +void DynamicServiceLoader::LoadLocalService( + const GURL& resolved_url, + scoped_refptr<LoadCallbacks> callbacks) { + base::FilePath path; + net::FileURLToFilePath(resolved_url, &path); + const bool kDeleteFileAfter = false; + + // Async for consistency with network case. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&DynamicServiceLoader::RunLibrary, + weak_ptr_factory_.GetWeakPtr(), + path, + callbacks, + kDeleteFileAfter, + base::PathExists(path))); +} + +void DynamicServiceLoader::LoadNetworkService( + const GURL& resolved_url, + scoped_refptr<LoadCallbacks> callbacks) { + if (!network_service_) { + context_->service_manager()->ConnectToService( + GURL("mojo:mojo_network_service"), + &network_service_); } - loader->Start(resolved_url, shell_handle.Pass(), context_); + if (!url_loader_) + network_service_->CreateURLLoader(Get(&url_loader_)); + + URLRequestPtr request(URLRequest::New()); + request->url = String::From(resolved_url); + request->auto_follow_redirects = true; + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableCache)) { + request->bypass_cache = true; + } + + url_loader_->Start( + request.Pass(), + base::Bind(&DynamicServiceLoader::OnLoadNetworkServiceComplete, + weak_ptr_factory_.GetWeakPtr(), + callbacks)); +} + +void DynamicServiceLoader::OnLoadNetworkServiceComplete( + scoped_refptr<LoadCallbacks> callbacks, URLResponsePtr response) { + if (response->error) { + LOG(ERROR) << "Error (" << response->error->code << ": " + << response->error->description << ") while fetching " + << response->url; + } + + MimeTypeToURLMap::iterator iter = + mime_type_to_url_.find(response->mime_type); + if (iter != mime_type_to_url_.end()) { + callbacks->LoadWithContentHandler(iter->second, response.Pass()); + return; + } + + base::FilePath file; + base::CreateTemporaryFile(&file); + + const bool kDeleteFileAfter = true; + common::CopyToFile(response->body.Pass(), + file, + context_->task_runners()->blocking_pool(), + base::Bind(&DynamicServiceLoader::RunLibrary, + weak_ptr_factory_.GetWeakPtr(), + file, + callbacks, + kDeleteFileAfter)); +} + +void DynamicServiceLoader::RunLibrary(const base::FilePath& path, + scoped_refptr<LoadCallbacks> callbacks, + bool delete_file_after, + bool path_exists) { + // TODO(aa): We need to create a runner, even if we're not going to use it, + // because it getting destroyed is what causes shell to shut down. If we don't + // create this, in the case where shell never successfully creates even one + // app, then shell will never shut down, because no runners are ever + // destroyed. + scoped_ptr<DynamicServiceRunner> runner(runner_factory_->Create(context_)); + if (!path_exists) + return; + + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; + + DynamicServiceRunner* runner_raw = runner.release(); + runner_raw->Start(path, + shell_handle.Pass(), + base::Bind(&RunLibraryComplete, + base::Unretained(runner_raw), + delete_file_after ? path : base::FilePath())); } void DynamicServiceLoader::OnServiceError(ServiceManager* manager, diff --git a/mojo/shell/dynamic_service_loader.h b/mojo/shell/dynamic_service_loader.h index 72bf093..0db2284 100644 --- a/mojo/shell/dynamic_service_loader.h +++ b/mojo/shell/dynamic_service_loader.h @@ -8,6 +8,7 @@ #include <map> #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "mojo/public/cpp/system/core.h" #include "mojo/service_manager/service_loader.h" #include "mojo/services/public/interfaces/network/network_service.mojom.h" @@ -30,17 +31,36 @@ class DynamicServiceLoader : public ServiceLoader { scoped_ptr<DynamicServiceRunnerFactory> runner_factory); virtual ~DynamicServiceLoader(); + void RegisterContentHandler(const std::string& mime_type, + const GURL& content_handler_url); + // ServiceLoader methods: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle service_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; private: + typedef std::map<std::string, GURL> MimeTypeToURLMap; + + void LoadLocalService(const GURL& resolved_url, + scoped_refptr<LoadCallbacks> callbacks); + void LoadNetworkService(const GURL& resolved_url, + scoped_refptr<LoadCallbacks> callbacks); + void OnLoadNetworkServiceComplete(scoped_refptr<LoadCallbacks> callbacks, + URLResponsePtr url_response); + void RunLibrary(const base::FilePath& response_file, + scoped_refptr<LoadCallbacks> callbacks, + bool delete_file_after, + bool response_path_exists); + Context* const context_; scoped_ptr<DynamicServiceRunnerFactory> runner_factory_; NetworkServicePtr network_service_; + URLLoaderPtr url_loader_; + MimeTypeToURLMap mime_type_to_url_; + base::WeakPtrFactory<DynamicServiceLoader> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(DynamicServiceLoader); }; diff --git a/mojo/shell/dynamic_service_loader_unittest.cc b/mojo/shell/dynamic_service_loader_unittest.cc index f70d115..915bcf1 100644 --- a/mojo/shell/dynamic_service_loader_unittest.cc +++ b/mojo/shell/dynamic_service_loader_unittest.cc @@ -73,7 +73,9 @@ TEST_F(DynamicServiceLoaderTest, DoesNotExist) { base::FilePath nonexistent_file(FILE_PATH_LITERAL("nonexistent.txt")); GURL url(net::FilePathToFileURL(temp_dir.path().Append(nonexistent_file))); MessagePipe pipe; - loader_->LoadService(context_.service_manager(), url, pipe.handle0.Pass()); + scoped_refptr<ServiceLoader::SimpleLoadCallbacks> callbacks( + new ServiceLoader::SimpleLoadCallbacks(pipe.handle0.Pass())); + loader_->Load(context_.service_manager(), url, callbacks); loop_.Run(); EXPECT_FALSE(state_.runner_was_started); EXPECT_TRUE(state_.runner_was_destroyed); diff --git a/mojo/shell/network_service_loader.cc b/mojo/shell/network_service_loader.cc index 9f8f87f..8e5cff2 100644 --- a/mojo/shell/network_service_loader.cc +++ b/mojo/shell/network_service_loader.cc @@ -29,10 +29,13 @@ NetworkServiceLoader::NetworkServiceLoader() { NetworkServiceLoader::~NetworkServiceLoader() { } -void NetworkServiceLoader::LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { +void NetworkServiceLoader::Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; + uintptr_t key = reinterpret_cast<uintptr_t>(manager); if (apps_.find(key) == apps_.end()) { scoped_ptr<ApplicationImpl> app( diff --git a/mojo/shell/network_service_loader.h b/mojo/shell/network_service_loader.h index 2184072..0eab765 100644 --- a/mojo/shell/network_service_loader.h +++ b/mojo/shell/network_service_loader.h @@ -31,10 +31,9 @@ class NetworkServiceLoader : public ServiceLoader, private: // ServiceLoader overrides: - virtual void LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; diff --git a/mojo/shell/switches.cc b/mojo/shell/switches.cc index c597218..cf3697f 100644 --- a/mojo/shell/switches.cc +++ b/mojo/shell/switches.cc @@ -10,6 +10,10 @@ namespace switches { // |ChildProcess::Type|). const char kChildProcessType[] = "child-process-type"; +// Comma separated list like: +// text/html,mojo://mojo_html_viewer,application/bravo,https://abarth.com/bravo +const char kContentHandlers[] = "content-handlers"; + // Force dynamically loaded apps / services to be loaded irrespective of cache // instructions. const char kDisableCache[] = "disable-cache"; diff --git a/mojo/shell/switches.h b/mojo/shell/switches.h index a1d4ac5..d2271cf 100644 --- a/mojo/shell/switches.h +++ b/mojo/shell/switches.h @@ -10,6 +10,7 @@ namespace switches { // All switches in alphabetical order. The switches should be documented // alongside the definition of their values in the .cc file. extern const char kChildProcessType[]; +extern const char kContentHandlers[]; extern const char kDisableCache[]; extern const char kEnableMultiprocess[]; extern const char kOrigin[]; diff --git a/mojo/shell/ui_service_loader_android.cc b/mojo/shell/ui_service_loader_android.cc index 3960858..e2f77464b 100644 --- a/mojo/shell/ui_service_loader_android.cc +++ b/mojo/shell/ui_service_loader_android.cc @@ -15,10 +15,12 @@ class UIServiceLoader::UILoader { explicit UILoader(ServiceLoader* loader) : loader_(loader) {} ~UILoader() {} - void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { - loader_->LoadService(manager, url, shell_handle.Pass()); + void Load(ServiceManager* manager, + const GURL& url, + ScopedMessagePipeHandle shell_handle) { + scoped_refptr<LoadCallbacks> callbacks( + new ServiceLoader::SimpleLoadCallbacks(shell_handle.Pass())); + loader_->Load(manager, url, callbacks); } void OnServiceError(ServiceManager* manager, const GURL& url) { @@ -42,17 +44,20 @@ UIServiceLoader::~UIServiceLoader() { base::Bind(&UIServiceLoader::ShutdownOnUIThread, base::Unretained(this))); } -void UIServiceLoader::LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { +void UIServiceLoader::Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; context_->ui_loop()->PostTask( FROM_HERE, - base::Bind( - &UIServiceLoader::LoadServiceOnUIThread, - base::Unretained(this), - manager, - url, - base::Owned(new ScopedMessagePipeHandle(shell_handle.Pass())))); + base::Bind(&UIServiceLoader::LoadOnUIThread, + base::Unretained(this), + manager, + url, + base::Owned( + new ScopedMessagePipeHandle(shell_handle.Pass())))); } void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) { @@ -64,13 +69,12 @@ void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) { url)); } -void UIServiceLoader::LoadServiceOnUIThread( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle* shell_handle) { +void UIServiceLoader::LoadOnUIThread(ServiceManager* manager, + const GURL& url, + ScopedMessagePipeHandle* shell_handle) { if (!ui_loader_) ui_loader_ = new UILoader(loader_.get()); - ui_loader_->LoadService(manager, url, shell_handle->Pass()); + ui_loader_->Load(manager, url, shell_handle->Pass()); } void UIServiceLoader::OnServiceErrorOnUIThread(ServiceManager* manager, diff --git a/mojo/shell/ui_service_loader_android.h b/mojo/shell/ui_service_loader_android.h index ebe6df9..8cce709 100644 --- a/mojo/shell/ui_service_loader_android.h +++ b/mojo/shell/ui_service_loader_android.h @@ -25,9 +25,9 @@ class UIServiceLoader : public ServiceLoader { virtual ~UIServiceLoader(); // ServiceLoader overrides: - virtual void LoadService(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; @@ -38,9 +38,9 @@ class UIServiceLoader : public ServiceLoader { // to |background_loader_| to do the actual loading. // TODO: having this code take a |manager| is fragile (as ServiceManager isn't // thread safe). - void LoadServiceOnUIThread(ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle* shell_handle); + void LoadOnUIThread(ServiceManager* manager, + const GURL& url, + ScopedMessagePipeHandle* shell_handle); void OnServiceErrorOnUIThread(ServiceManager* manager, const GURL& url); void ShutdownOnUIThread(); diff --git a/mojo/shell/view_manager_loader.cc b/mojo/shell/view_manager_loader.cc index bbcca5a..d53accc 100644 --- a/mojo/shell/view_manager_loader.cc +++ b/mojo/shell/view_manager_loader.cc @@ -20,10 +20,13 @@ ViewManagerLoader::ViewManagerLoader() { ViewManagerLoader::~ViewManagerLoader() { } -void ViewManagerLoader::LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) { +void ViewManagerLoader::Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) { + ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); + if (!shell_handle.is_valid()) + return; + // TODO(sky): this needs some sort of authentication as well as making sure // we only ever have one active at a time. scoped_ptr<ApplicationImpl> app( diff --git a/mojo/shell/view_manager_loader.h b/mojo/shell/view_manager_loader.h index bb3a615..6827bac 100644 --- a/mojo/shell/view_manager_loader.h +++ b/mojo/shell/view_manager_loader.h @@ -30,10 +30,9 @@ class ViewManagerLoader private: // ServiceLoader overrides: - virtual void LoadService( - ServiceManager* manager, - const GURL& url, - ScopedMessagePipeHandle shell_handle) OVERRIDE; + virtual void Load(ServiceManager* manager, + const GURL& url, + scoped_refptr<LoadCallbacks> callbacks) OVERRIDE; virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE; |