summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 17:16:10 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 17:16:10 +0000
commite858750e720f24cd981b4222b025757d1f08bc3d (patch)
treed90277c6bc05882c563a61e2112b5da8125a97b3 /mojo
parentbdab4937e356c11f6ab53c9bdce595354e812b2d (diff)
downloadchromium_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')
-rw-r--r--mojo/examples/content_handler_demo/content_handler_demo.cc89
-rw-r--r--mojo/mojo.gyp4
-rw-r--r--mojo/mojo_examples.gypi16
-rw-r--r--mojo/mojo_services.gypi17
-rw-r--r--mojo/service_manager/BUILD.gn3
-rw-r--r--mojo/service_manager/background_shell_service_loader.cc28
-rw-r--r--mojo/service_manager/background_shell_service_loader.h13
-rw-r--r--mojo/service_manager/background_shell_service_loader_unittest.cc10
-rw-r--r--mojo/service_manager/service_loader.cc29
-rw-r--r--mojo/service_manager/service_loader.h52
-rw-r--r--mojo/service_manager/service_manager.cc139
-rw-r--r--mojo/service_manager/service_manager.h24
-rw-r--r--mojo/service_manager/service_manager_unittest.cc20
-rw-r--r--mojo/services/BUILD.gn1
-rw-r--r--mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc9
-rw-r--r--mojo/services/public/interfaces/content_handler/BUILD.gn17
-rw-r--r--mojo/services/public/interfaces/content_handler/content_handler.mojom16
-rw-r--r--mojo/services/view_manager/view_manager_unittest.cc9
-rw-r--r--mojo/services/window_manager/window_manager_api_unittest.cc9
-rw-r--r--mojo/shell/context.cc56
-rw-r--r--mojo/shell/dbus_service_loader_linux.cc12
-rw-r--r--mojo/shell/dbus_service_loader_linux.h6
-rw-r--r--mojo/shell/dynamic_service_loader.cc249
-rw-r--r--mojo/shell/dynamic_service_loader.h26
-rw-r--r--mojo/shell/dynamic_service_loader_unittest.cc4
-rw-r--r--mojo/shell/network_service_loader.cc11
-rw-r--r--mojo/shell/network_service_loader.h7
-rw-r--r--mojo/shell/switches.cc4
-rw-r--r--mojo/shell/switches.h1
-rw-r--r--mojo/shell/ui_service_loader_android.cc40
-rw-r--r--mojo/shell/ui_service_loader_android.h12
-rw-r--r--mojo/shell/view_manager_loader.cc11
-rw-r--r--mojo/shell/view_manager_loader.h7
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;