Commit 40e54f85 authored by aa@chromium.org's avatar aa@chromium.org

Reland r288013: First cut at "content handling" support in Mojo.

TBR=darin@chromium.org

Review URL: https://codereview.chromium.org/456533002

Cr-Commit-Position: refs/heads/master@{#288383}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288383 0039d316-1c4b-4281-b951-d872f2087c98
parent 1c2a5a5e
// 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
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
'mojo_base.gyp:mojo_base', 'mojo_base.gyp:mojo_base',
'mojo_apps_js_unittests', 'mojo_apps_js_unittests',
'mojo_compositor_app', 'mojo_compositor_app',
'mojo_content_handler_demo',
'mojo_echo_client', 'mojo_echo_client',
'mojo_echo_service', 'mojo_echo_service',
'mojo_example_apptests', 'mojo_example_apptests',
...@@ -341,6 +342,8 @@ ...@@ -341,6 +342,8 @@
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../net/net.gyp:net', '../net/net.gyp:net',
'../url/url.gyp:url_lib', '../url/url.gyp:url_lib',
'mojo_content_handler_bindings',
'mojo_network_bindings',
'mojo_base.gyp:mojo_application_bindings', 'mojo_base.gyp:mojo_application_bindings',
'mojo_base.gyp:mojo_common_lib', 'mojo_base.gyp:mojo_common_lib',
'mojo_base.gyp:mojo_environment_chromium', 'mojo_base.gyp:mojo_environment_chromium',
...@@ -349,6 +352,7 @@ ...@@ -349,6 +352,7 @@
'sources': [ 'sources': [
'service_manager/background_shell_service_loader.cc', 'service_manager/background_shell_service_loader.cc',
'service_manager/background_shell_service_loader.h', 'service_manager/background_shell_service_loader.h',
'service_manager/service_loader.cc',
'service_manager/service_loader.h', 'service_manager/service_loader.h',
'service_manager/service_manager.cc', 'service_manager/service_manager.cc',
'service_manager/service_manager.h', 'service_manager/service_manager.h',
......
...@@ -204,6 +204,22 @@ ...@@ -204,6 +204,22 @@
'public/cpp/application/lib/mojo_main_standalone.cc', 'public/cpp/application/lib/mojo_main_standalone.cc',
], ],
}, },
{
'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', 'target_name': 'package_mojo_wget',
'variables': { 'variables': {
......
...@@ -364,6 +364,23 @@ ...@@ -364,6 +364,23 @@
'mojo_network_bindings', 'mojo_network_bindings',
], ],
}, },
{
# 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 # GN version: //mojo/services/public/interfaces/network
'target_name': 'mojo_network_bindings', 'target_name': 'mojo_network_bindings',
......
...@@ -8,6 +8,7 @@ component("service_manager") { ...@@ -8,6 +8,7 @@ component("service_manager") {
sources = [ sources = [
"background_shell_service_loader.cc", "background_shell_service_loader.cc",
"background_shell_service_loader.h", "background_shell_service_loader.h",
"service_loader.cc",
"service_loader.h", "service_loader.h",
"service_manager.cc", "service_manager.cc",
"service_manager.h", "service_manager.h",
...@@ -24,6 +25,8 @@ component("service_manager") { ...@@ -24,6 +25,8 @@ component("service_manager") {
"//mojo/common", "//mojo/common",
"//mojo/environment:chromium", "//mojo/environment:chromium",
"//mojo/public/interfaces/application:application", "//mojo/public/interfaces/application:application",
"//mojo/services/public/interfaces/content_handler:content_handler",
"//mojo/services/public/interfaces/network:network",
"//mojo/system", "//mojo/system",
] ]
......
...@@ -15,10 +15,12 @@ class BackgroundShellServiceLoader::BackgroundLoader { ...@@ -15,10 +15,12 @@ class BackgroundShellServiceLoader::BackgroundLoader {
explicit BackgroundLoader(ServiceLoader* loader) : loader_(loader) {} explicit BackgroundLoader(ServiceLoader* loader) : loader_(loader) {}
~BackgroundLoader() {} ~BackgroundLoader() {}
void LoadService(ServiceManager* manager, void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) { ScopedMessagePipeHandle shell_handle) {
loader_->LoadService(manager, url, shell_handle.Pass()); scoped_refptr<LoadCallbacks> callbacks(
new ServiceLoader::SimpleLoadCallbacks(shell_handle.Pass()));
loader_->Load(manager, url, callbacks);
} }
void OnServiceError(ServiceManager* manager, const GURL& url) { void OnServiceError(ServiceManager* manager, const GURL& url) {
...@@ -47,17 +49,21 @@ BackgroundShellServiceLoader::~BackgroundShellServiceLoader() { ...@@ -47,17 +49,21 @@ BackgroundShellServiceLoader::~BackgroundShellServiceLoader() {
thread_->Join(); thread_->Join();
} }
void BackgroundShellServiceLoader::LoadService( void BackgroundShellServiceLoader::Load(
ServiceManager* manager, ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) { scoped_refptr<LoadCallbacks> callbacks) {
ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
if (!thread_) { 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 // result in a new thread like DynamicService{Loader, Runner}. But some
// loaders are creating multiple ApplicationImpls (NetworkServiceLoader) // loaders are creating multiple ApplicationImpls (NetworkServiceLoader)
// sharing a delegate (etc). So we have to keep it single threaded, wait // 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 // 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_.reset(new base::DelegateSimpleThread(this, thread_name_));
thread_->Start(); thread_->Start();
message_loop_created_.Wait(); message_loop_created_.Wait();
...@@ -65,7 +71,7 @@ void BackgroundShellServiceLoader::LoadService( ...@@ -65,7 +71,7 @@ void BackgroundShellServiceLoader::LoadService(
} }
task_runner_->PostTask(FROM_HERE, task_runner_->PostTask(FROM_HERE,
base::Bind(&BackgroundShellServiceLoader::LoadServiceOnBackgroundThread, base::Bind(&BackgroundShellServiceLoader::LoadOnBackgroundThread,
base::Unretained(this), manager, url, base::Unretained(this), manager, url,
base::Owned( base::Owned(
new ScopedMessagePipeHandle(shell_handle.Pass())))); new ScopedMessagePipeHandle(shell_handle.Pass()))));
...@@ -93,14 +99,14 @@ void BackgroundShellServiceLoader::Run() { ...@@ -93,14 +99,14 @@ void BackgroundShellServiceLoader::Run() {
loader_.reset(); loader_.reset();
} }
void BackgroundShellServiceLoader::LoadServiceOnBackgroundThread( void BackgroundShellServiceLoader::LoadOnBackgroundThread(
ServiceManager* manager, ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle* shell_handle) { ScopedMessagePipeHandle* shell_handle) {
DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK(task_runner_->RunsTasksOnCurrentThread());
if (!background_loader_) if (!background_loader_)
background_loader_ = new BackgroundLoader(loader_.get()); 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( void BackgroundShellServiceLoader::OnServiceErrorOnBackgroundThread(
......
...@@ -26,9 +26,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader : ...@@ -26,9 +26,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader :
virtual ~BackgroundShellServiceLoader(); virtual ~BackgroundShellServiceLoader();
// ServiceLoader overrides: // ServiceLoader overrides:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE; scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
const GURL& url) OVERRIDE; const GURL& url) OVERRIDE;
...@@ -42,10 +42,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader : ...@@ -42,10 +42,9 @@ class MOJO_SERVICE_MANAGER_EXPORT BackgroundShellServiceLoader :
// to |background_loader_| to do the actual loading. // to |background_loader_| to do the actual loading.
// TODO: having this code take a |manager| is fragile (as ServiceManager isn't // TODO: having this code take a |manager| is fragile (as ServiceManager isn't
// thread safe). // thread safe).
void LoadServiceOnBackgroundThread( void LoadOnBackgroundThread(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, ScopedMessagePipeHandle* shell_handle);
ScopedMessagePipeHandle* shell_handle);
void OnServiceErrorOnBackgroundThread(ServiceManager* manager, void OnServiceErrorOnBackgroundThread(ServiceManager* manager,
const GURL& url); const GURL& url);
bool quit_on_shutdown_; bool quit_on_shutdown_;
......
...@@ -16,9 +16,9 @@ class DummyLoader : public ServiceLoader { ...@@ -16,9 +16,9 @@ class DummyLoader : public ServiceLoader {
virtual ~DummyLoader() {} virtual ~DummyLoader() {}
// ServiceLoader overrides: // ServiceLoader overrides:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE { scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
if (simulate_app_quit_) if (simulate_app_quit_)
base::MessageLoop::current()->Quit(); base::MessageLoop::current()->Quit();
} }
...@@ -49,7 +49,9 @@ TEST(BackgroundShellServiceLoaderTest, Load) { ...@@ -49,7 +49,9 @@ TEST(BackgroundShellServiceLoaderTest, Load) {
BackgroundShellServiceLoader loader(real_loader.Pass(), "test", BackgroundShellServiceLoader loader(real_loader.Pass(), "test",
base::MessageLoop::TYPE_DEFAULT); base::MessageLoop::TYPE_DEFAULT);
MessagePipe dummy; 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 } // namespace mojo
// 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
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#ifndef MOJO_SERVICE_MANAGER_SERVICE_LOADER_H_ #ifndef MOJO_SERVICE_MANAGER_SERVICE_LOADER_H_
#define 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/public/cpp/system/core.h"
#include "mojo/service_manager/service_manager_export.h" #include "mojo/service_manager/service_manager_export.h"
#include "mojo/services/public/interfaces/network/url_loader.mojom.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace mojo { namespace mojo {
...@@ -23,10 +25,54 @@ class ServiceManager; ...@@ -23,10 +25,54 @@ class ServiceManager;
// apps and services. // apps and services.
class MOJO_SERVICE_MANAGER_EXPORT ServiceLoader { class MOJO_SERVICE_MANAGER_EXPORT ServiceLoader {
public: 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 ~ServiceLoader() {}
virtual void LoadService(ServiceManager* manager,
const GURL& url, // Load the application named |url|. Applications can be loaded two ways:
ScopedMessagePipeHandle shell_handle) = 0; //
// 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; virtual void OnServiceError(ServiceManager* manager, const GURL& url) = 0;
protected: protected:
......
...@@ -2,18 +2,21 @@ ...@@ -2,18 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <stdio.h>
#include "mojo/service_manager/service_manager.h" #include "mojo/service_manager/service_manager.h"
#include <stdio.h>
#include "base/bind.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "mojo/common/common_type_converters.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/application.mojom.h"
#include "mojo/public/interfaces/application/shell.mojom.h" #include "mojo/public/interfaces/application/shell.mojom.h"
#include "mojo/service_manager/service_loader.h" #include "mojo/service_manager/service_loader.h"
#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
namespace mojo { namespace mojo {
...@@ -33,7 +36,52 @@ class StubServiceProvider : public InterfaceImpl<ServiceProvider> { ...@@ -33,7 +36,52 @@ class StubServiceProvider : public InterfaceImpl<ServiceProvider> {
ScopedMessagePipeHandle client_handle) MOJO_OVERRIDE {} 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> { class ServiceManager::ShellImpl : public InterfaceImpl<Shell> {
public: public:
...@@ -76,6 +124,21 @@ class ServiceManager::ShellImpl : public InterfaceImpl<Shell> { ...@@ -76,6 +124,21 @@ class ServiceManager::ShellImpl : public InterfaceImpl<Shell> {
DISALLOW_COPY_AND_ASSIGN(ShellImpl); 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 // static
ServiceManager::TestAPI::TestAPI(ServiceManager* manager) : manager_(manager) { ServiceManager::TestAPI::TestAPI(ServiceManager* manager) : manager_(manager) {
} }
...@@ -92,10 +155,13 @@ bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const { ...@@ -92,10 +155,13 @@ bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const {
manager_->url_to_shell_impl_.end(); manager_->url_to_shell_impl_.end();
} }
ServiceManager::ServiceManager() : interceptor_(NULL) { ServiceManager::ServiceManager()
: interceptor_(NULL),
weak_ptr_factory_(this) {
} }
ServiceManager::~ServiceManager() { ServiceManager::~ServiceManager() {
STLDeleteValues(&url_to_content_handler_);
TerminateShellConnections(); TerminateShellConnections();
STLDeleteValues(&url_to_loader_); STLDeleteValues(&url_to_loader_);
STLDeleteValues(&scheme_to_loader_); STLDeleteValues(&scheme_to_loader_);
...@@ -117,15 +183,24 @@ void ServiceManager::ConnectToApplication(const GURL& url, ...@@ -117,15 +183,24 @@ void ServiceManager::ConnectToApplication(const GURL& url,
const GURL& requestor_url, const GURL& requestor_url,
ServiceProviderPtr service_provider) { ServiceProviderPtr service_provider) {
URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url); URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url);
ShellImpl* shell_impl;
if (shell_it != url_to_shell_impl_.end()) { if (shell_it != url_to_shell_impl_.end()) {
shell_impl = shell_it->second; ConnectToClient(shell_it->second, url, requestor_url,
} else { service_provider.Pass());
MessagePipe pipe; return;
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;
} }
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_) { if (interceptor_) {
shell_impl->ConnectToClient( shell_impl->ConnectToClient(
requestor_url, requestor_url,
...@@ -135,6 +210,48 @@ void ServiceManager::ConnectToApplication(const GURL& 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, void ServiceManager::SetLoaderForURL(scoped_ptr<ServiceLoader> loader,
const GURL& url) { const GURL& url) {
URLToLoaderMap::iterator it = url_to_loader_.find(url); URLToLoaderMap::iterator it = url_to_loader_.find(url);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h" #include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "mojo/service_manager/service_loader.h" #include "mojo/service_manager/service_loader.h"
#include "mojo/service_manager/service_manager_export.h" #include "mojo/service_manager/service_manager_export.h"
...@@ -87,10 +88,30 @@ class MOJO_SERVICE_MANAGER_EXPORT ServiceManager { ...@@ -87,10 +88,30 @@ class MOJO_SERVICE_MANAGER_EXPORT ServiceManager {
void TerminateShellConnections(); void TerminateShellConnections();
private: private:
struct ContentHandlerConnection;
class LoadCallbacksImpl;
class ShellImpl; class ShellImpl;
typedef std::map<std::string, ServiceLoader*> SchemeToLoaderMap; typedef std::map<std::string, ServiceLoader*> SchemeToLoaderMap;
typedef std::map<GURL, ServiceLoader*> URLToLoaderMap; typedef std::map<GURL, ServiceLoader*> URLToLoaderMap;
typedef std::map<GURL, ShellImpl*> URLToShellImplMap; 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.) // 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, // 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 { ...@@ -107,6 +128,9 @@ class MOJO_SERVICE_MANAGER_EXPORT ServiceManager {
Interceptor* interceptor_; Interceptor* interceptor_;
URLToShellImplMap url_to_shell_impl_; URLToShellImplMap url_to_shell_impl_;
URLToContentHandlerMap url_to_content_handler_;
base::WeakPtrFactory<ServiceManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceManager); DISALLOW_COPY_AND_ASSIGN(ServiceManager);
}; };
......
...@@ -118,12 +118,12 @@ class TestServiceLoader : public ServiceLoader, ...@@ -118,12 +118,12 @@ class TestServiceLoader : public ServiceLoader,
private: private:
// ServiceLoader implementation. // ServiceLoader implementation.
virtual void LoadService( virtual void Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
ScopedMessagePipeHandle service_provider_handle) OVERRIDE {
++num_loads_; ++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, virtual void OnServiceError(ServiceManager* manager,
...@@ -332,11 +332,11 @@ class Tester : public ApplicationDelegate, ...@@ -332,11 +332,11 @@ class Tester : public ApplicationDelegate,
virtual ~Tester() {} virtual ~Tester() {}
private: private:
virtual void LoadService( virtual void Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
ScopedMessagePipeHandle shell_handle) OVERRIDE { app_.reset(
app_.reset(new ApplicationImpl(this, shell_handle.Pass())); new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
} }
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
......
...@@ -6,6 +6,7 @@ group("services") { ...@@ -6,6 +6,7 @@ group("services") {
deps = [ deps = [
"//mojo/services/dbus_echo:bindings", "//mojo/services/dbus_echo:bindings",
"//mojo/services/gles2:bindings", "//mojo/services/gles2:bindings",
"//mojo/services/public/interfaces/content_handler",
"//mojo/services/public/interfaces/input_events", "//mojo/services/public/interfaces/input_events",
"//mojo/services/public/interfaces/geometry", "//mojo/services/public/interfaces/geometry",
"//mojo/services/public/interfaces/native_viewport", "//mojo/services/public/interfaces/native_viewport",
......
...@@ -55,9 +55,12 @@ class ConnectServiceLoader : public ServiceLoader, ...@@ -55,9 +55,12 @@ class ConnectServiceLoader : public ServiceLoader,
private: private:
// Overridden from ServiceLoader: // Overridden from ServiceLoader:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE { scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this, scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this,
shell_handle.Pass())); shell_handle.Pass()));
apps_.push_back(app.release()); apps_.push_back(app.release());
......
# 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",
]
}
// 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);
};
}
...@@ -386,9 +386,12 @@ class EmbedServiceLoader : public ServiceLoader, ...@@ -386,9 +386,12 @@ class EmbedServiceLoader : public ServiceLoader,
virtual ~EmbedServiceLoader() {} virtual ~EmbedServiceLoader() {}
// ServiceLoader implementation: // ServiceLoader implementation:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE { scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this, scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this,
shell_handle.Pass())); shell_handle.Pass()));
apps_.push_back(app.release()); apps_.push_back(app.release());
......
...@@ -132,9 +132,12 @@ class TestServiceLoader : public ServiceLoader, ...@@ -132,9 +132,12 @@ class TestServiceLoader : public ServiceLoader,
private: private:
// Overridden from ServiceLoader: // Overridden from ServiceLoader:
virtual void LoadService(ServiceManager* service_manager, virtual void Load(ServiceManager* service_manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) MOJO_OVERRIDE { scoped_refptr<LoadCallbacks> callbacks) MOJO_OVERRIDE {
ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
scoped_ptr<ApplicationImpl> app( scoped_ptr<ApplicationImpl> app(
new ApplicationImpl(this, shell_handle.Pass())); new ApplicationImpl(this, shell_handle.Pass()));
apps_.push_back(app.release()); apps_.push_back(app.release());
......
...@@ -4,10 +4,13 @@ ...@@ -4,10 +4,13 @@
#include "mojo/shell/context.h" #include "mojo/shell/context.h"
#include <vector>
#include "build/build_config.h" #include "build/build_config.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/memory/scoped_vector.h" #include "base/memory/scoped_vector.h"
#include "base/strings/string_split.h"
#include "mojo/embedder/embedder.h" #include "mojo/embedder/embedder.h"
#include "mojo/gles2/gles2_support_impl.h" #include "mojo/gles2/gles2_support_impl.h"
#include "mojo/public/cpp/application/application_impl.h" #include "mojo/public/cpp/application/application_impl.h"
...@@ -61,6 +64,32 @@ class Setup { ...@@ -61,6 +64,32 @@ class Setup {
static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER; 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 } // namespace
class Context::NativeViewportServiceLoader : public ServiceLoader { class Context::NativeViewportServiceLoader : public ServiceLoader {
...@@ -69,10 +98,12 @@ class Context::NativeViewportServiceLoader : public ServiceLoader { ...@@ -69,10 +98,12 @@ class Context::NativeViewportServiceLoader : public ServiceLoader {
virtual ~NativeViewportServiceLoader() {} virtual ~NativeViewportServiceLoader() {}
private: private:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE { scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
app_.reset(services::CreateNativeViewportService(shell_handle.Pass())); ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (shell_handle.is_valid())
app_.reset(services::CreateNativeViewportService(shell_handle.Pass()));
} }
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
...@@ -95,16 +126,19 @@ void Context::Init() { ...@@ -95,16 +126,19 @@ void Context::Init() {
for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i) for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i)
mojo_url_resolver_.AddLocalFileMapping(GURL(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; scoped_ptr<DynamicServiceRunnerFactory> runner_factory;
if (cmdline->HasSwitch(switches::kEnableMultiprocess)) if (command_line->HasSwitch(switches::kEnableMultiprocess))
runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory()); runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory());
else else
runner_factory.reset(new InProcessDynamicServiceRunnerFactory()); 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( service_manager_.set_default_loader(
scoped_ptr<ServiceLoader>( scoped_ptr<ServiceLoader>(dynamic_service_loader));
new DynamicServiceLoader(this, runner_factory.Pass())));
// The native viewport service synchronously waits for certain messages. If we // 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 // 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. // viewport should run its own process so that this isn't an issue.
...@@ -140,9 +174,9 @@ void Context::Init() { ...@@ -140,9 +174,9 @@ void Context::Init() {
"dbus"); "dbus");
#endif // defined(OS_LINUX) #endif // defined(OS_LINUX)
if (cmdline->HasSwitch(switches::kSpy)) { if (command_line->HasSwitch(switches::kSpy)) {
spy_.reset(new mojo::Spy(&service_manager_, spy_.reset(new mojo::Spy(
cmdline->GetSwitchValueASCII(switches::kSpy))); &service_manager_, command_line->GetSwitchValueASCII(switches::kSpy)));
} }
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
......
...@@ -150,9 +150,15 @@ DBusServiceLoader::~DBusServiceLoader() { ...@@ -150,9 +150,15 @@ DBusServiceLoader::~DBusServiceLoader() {
DCHECK(url_to_load_context_.empty()); DCHECK(url_to_load_context_.empty());
} }
void DBusServiceLoader::LoadService(ServiceManager* manager, void DBusServiceLoader::Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) { 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.SchemeIs("dbus"));
DCHECK(url_to_load_context_.find(url) == url_to_load_context_.end()); DCHECK(url_to_load_context_.find(url) == url_to_load_context_.end());
url_to_load_context_[url] = url_to_load_context_[url] =
......
...@@ -61,9 +61,9 @@ class DBusServiceLoader : public ServiceLoader { ...@@ -61,9 +61,9 @@ class DBusServiceLoader : public ServiceLoader {
// the name "org.chromium.EchoService" and invoke the method // the name "org.chromium.EchoService" and invoke the method
// "org.chromium.Mojo.ConnectChannel" on the object exported at // "org.chromium.Mojo.ConnectChannel" on the object exported at
// "/org/chromium/MojoImpl". // "/org/chromium/MojoImpl".
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE; scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, const GURL& url) virtual void OnServiceError(ServiceManager* manager, const GURL& url)
OVERRIDE; OVERRIDE;
......
...@@ -20,122 +20,15 @@ ...@@ -20,122 +20,15 @@
namespace mojo { namespace mojo {
namespace shell { 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) { namespace {
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_)));
}
Context* context_; void RunLibraryComplete(DynamicServiceRunner* runner,
NetworkServicePtr network_service_; const base::FilePath& temp_file) {
URLLoaderPtr url_loader_; delete runner;
ScopedMessagePipeHandle service_handle_; if (!temp_file.empty())
base::FilePath file_; base::DeleteFile(temp_file, false);
}; }
} // namespace } // namespace
...@@ -143,17 +36,22 @@ DynamicServiceLoader::DynamicServiceLoader( ...@@ -143,17 +36,22 @@ DynamicServiceLoader::DynamicServiceLoader(
Context* context, Context* context,
scoped_ptr<DynamicServiceRunnerFactory> runner_factory) scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
: context_(context), : context_(context),
runner_factory_(runner_factory.Pass()) { runner_factory_(runner_factory.Pass()),
weak_ptr_factory_(this) {
} }
DynamicServiceLoader::~DynamicServiceLoader() { DynamicServiceLoader::~DynamicServiceLoader() {
} }
void DynamicServiceLoader::LoadService(ServiceManager* manager, void DynamicServiceLoader::RegisterContentHandler(
const GURL& url, const std::string& mime_type,
ScopedMessagePipeHandle shell_handle) { const GURL& content_handler_url) {
scoped_ptr<DynamicServiceRunner> runner = runner_factory_->Create(context_); mime_type_to_url_[mime_type] = content_handler_url;
}
void DynamicServiceLoader::Load(ServiceManager* manager,
const GURL& url,
scoped_refptr<LoadCallbacks> callbacks) {
GURL resolved_url; GURL resolved_url;
if (url.SchemeIs("mojo")) { if (url.SchemeIs("mojo")) {
resolved_url = context_->mojo_url_resolver()->Resolve(url); resolved_url = context_->mojo_url_resolver()->Resolve(url);
...@@ -161,18 +59,109 @@ void DynamicServiceLoader::LoadService(ServiceManager* manager, ...@@ -161,18 +59,109 @@ void DynamicServiceLoader::LoadService(ServiceManager* manager,
resolved_url = url; resolved_url = url;
} }
Loader* loader; if (resolved_url.SchemeIsFile())
if (resolved_url.SchemeIsFile()) { LoadLocalService(resolved_url, callbacks);
loader = new LocalLoader(runner.Pass()); else
} else { LoadNetworkService(resolved_url, callbacks);
if (!network_service_) { }
context_->service_manager()->ConnectToService(
GURL("mojo:mojo_network_service"), void DynamicServiceLoader::LoadLocalService(
&network_service_); const GURL& resolved_url,
} scoped_refptr<LoadCallbacks> callbacks) {
loader = new NetworkLoader(runner.Pass(), network_service_.get()); 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, void DynamicServiceLoader::OnServiceError(ServiceManager* manager,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <map> #include <map>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/system/core.h" #include "mojo/public/cpp/system/core.h"
#include "mojo/service_manager/service_loader.h" #include "mojo/service_manager/service_loader.h"
#include "mojo/services/public/interfaces/network/network_service.mojom.h" #include "mojo/services/public/interfaces/network/network_service.mojom.h"
...@@ -30,17 +31,36 @@ class DynamicServiceLoader : public ServiceLoader { ...@@ -30,17 +31,36 @@ class DynamicServiceLoader : public ServiceLoader {
scoped_ptr<DynamicServiceRunnerFactory> runner_factory); scoped_ptr<DynamicServiceRunnerFactory> runner_factory);
virtual ~DynamicServiceLoader(); virtual ~DynamicServiceLoader();
void RegisterContentHandler(const std::string& mime_type,
const GURL& content_handler_url);
// ServiceLoader methods: // ServiceLoader methods:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle service_handle) OVERRIDE; scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, const GURL& url) virtual void OnServiceError(ServiceManager* manager, const GURL& url)
OVERRIDE; OVERRIDE;
private: 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_; Context* const context_;
scoped_ptr<DynamicServiceRunnerFactory> runner_factory_; scoped_ptr<DynamicServiceRunnerFactory> runner_factory_;
NetworkServicePtr network_service_; NetworkServicePtr network_service_;
URLLoaderPtr url_loader_;
MimeTypeToURLMap mime_type_to_url_;
base::WeakPtrFactory<DynamicServiceLoader> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DynamicServiceLoader); DISALLOW_COPY_AND_ASSIGN(DynamicServiceLoader);
}; };
......
...@@ -73,7 +73,9 @@ TEST_F(DynamicServiceLoaderTest, DoesNotExist) { ...@@ -73,7 +73,9 @@ TEST_F(DynamicServiceLoaderTest, DoesNotExist) {
base::FilePath nonexistent_file(FILE_PATH_LITERAL("nonexistent.txt")); base::FilePath nonexistent_file(FILE_PATH_LITERAL("nonexistent.txt"));
GURL url(net::FilePathToFileURL(temp_dir.path().Append(nonexistent_file))); GURL url(net::FilePathToFileURL(temp_dir.path().Append(nonexistent_file)));
MessagePipe pipe; 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(); loop_.Run();
EXPECT_FALSE(state_.runner_was_started); EXPECT_FALSE(state_.runner_was_started);
EXPECT_TRUE(state_.runner_was_destroyed); EXPECT_TRUE(state_.runner_was_destroyed);
......
...@@ -29,10 +29,13 @@ NetworkServiceLoader::NetworkServiceLoader() { ...@@ -29,10 +29,13 @@ NetworkServiceLoader::NetworkServiceLoader() {
NetworkServiceLoader::~NetworkServiceLoader() { NetworkServiceLoader::~NetworkServiceLoader() {
} }
void NetworkServiceLoader::LoadService( void NetworkServiceLoader::Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) {
ScopedMessagePipeHandle shell_handle) { ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
uintptr_t key = reinterpret_cast<uintptr_t>(manager); uintptr_t key = reinterpret_cast<uintptr_t>(manager);
if (apps_.find(key) == apps_.end()) { if (apps_.find(key) == apps_.end()) {
scoped_ptr<ApplicationImpl> app( scoped_ptr<ApplicationImpl> app(
......
...@@ -31,10 +31,9 @@ class NetworkServiceLoader : public ServiceLoader, ...@@ -31,10 +31,9 @@ class NetworkServiceLoader : public ServiceLoader,
private: private:
// ServiceLoader overrides: // ServiceLoader overrides:
virtual void LoadService( virtual void Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
ScopedMessagePipeHandle shell_handle) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
const GURL& url) OVERRIDE; const GURL& url) OVERRIDE;
......
...@@ -10,6 +10,10 @@ namespace switches { ...@@ -10,6 +10,10 @@ namespace switches {
// |ChildProcess::Type|). // |ChildProcess::Type|).
const char kChildProcessType[] = "child-process-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 // Force dynamically loaded apps / services to be loaded irrespective of cache
// instructions. // instructions.
const char kDisableCache[] = "disable-cache"; const char kDisableCache[] = "disable-cache";
......
...@@ -10,6 +10,7 @@ namespace switches { ...@@ -10,6 +10,7 @@ namespace switches {
// All switches in alphabetical order. The switches should be documented // All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file. // alongside the definition of their values in the .cc file.
extern const char kChildProcessType[]; extern const char kChildProcessType[];
extern const char kContentHandlers[];
extern const char kDisableCache[]; extern const char kDisableCache[];
extern const char kEnableMultiprocess[]; extern const char kEnableMultiprocess[];
extern const char kOrigin[]; extern const char kOrigin[];
......
...@@ -15,10 +15,12 @@ class UIServiceLoader::UILoader { ...@@ -15,10 +15,12 @@ class UIServiceLoader::UILoader {
explicit UILoader(ServiceLoader* loader) : loader_(loader) {} explicit UILoader(ServiceLoader* loader) : loader_(loader) {}
~UILoader() {} ~UILoader() {}
void LoadService(ServiceManager* manager, void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) { ScopedMessagePipeHandle shell_handle) {
loader_->LoadService(manager, url, shell_handle.Pass()); scoped_refptr<LoadCallbacks> callbacks(
new ServiceLoader::SimpleLoadCallbacks(shell_handle.Pass()));
loader_->Load(manager, url, callbacks);
} }
void OnServiceError(ServiceManager* manager, const GURL& url) { void OnServiceError(ServiceManager* manager, const GURL& url) {
...@@ -42,17 +44,20 @@ UIServiceLoader::~UIServiceLoader() { ...@@ -42,17 +44,20 @@ UIServiceLoader::~UIServiceLoader() {
base::Bind(&UIServiceLoader::ShutdownOnUIThread, base::Unretained(this))); base::Bind(&UIServiceLoader::ShutdownOnUIThread, base::Unretained(this)));
} }
void UIServiceLoader::LoadService(ServiceManager* manager, void UIServiceLoader::Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) { scoped_refptr<LoadCallbacks> callbacks) {
ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
context_->ui_loop()->PostTask( context_->ui_loop()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind( base::Bind(&UIServiceLoader::LoadOnUIThread,
&UIServiceLoader::LoadServiceOnUIThread, base::Unretained(this),
base::Unretained(this), manager,
manager, url,
url, base::Owned(
base::Owned(new ScopedMessagePipeHandle(shell_handle.Pass())))); new ScopedMessagePipeHandle(shell_handle.Pass()))));
} }
void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) { void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) {
...@@ -64,13 +69,12 @@ void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) { ...@@ -64,13 +69,12 @@ void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) {
url)); url));
} }
void UIServiceLoader::LoadServiceOnUIThread( void UIServiceLoader::LoadOnUIThread(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, ScopedMessagePipeHandle* shell_handle) {
ScopedMessagePipeHandle* shell_handle) {
if (!ui_loader_) if (!ui_loader_)
ui_loader_ = new UILoader(loader_.get()); 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, void UIServiceLoader::OnServiceErrorOnUIThread(ServiceManager* manager,
......
...@@ -25,9 +25,9 @@ class UIServiceLoader : public ServiceLoader { ...@@ -25,9 +25,9 @@ class UIServiceLoader : public ServiceLoader {
virtual ~UIServiceLoader(); virtual ~UIServiceLoader();
// ServiceLoader overrides: // ServiceLoader overrides:
virtual void LoadService(ServiceManager* manager, virtual void Load(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE; scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
const GURL& url) OVERRIDE; const GURL& url) OVERRIDE;
...@@ -38,9 +38,9 @@ class UIServiceLoader : public ServiceLoader { ...@@ -38,9 +38,9 @@ class UIServiceLoader : public ServiceLoader {
// to |background_loader_| to do the actual loading. // to |background_loader_| to do the actual loading.
// TODO: having this code take a |manager| is fragile (as ServiceManager isn't // TODO: having this code take a |manager| is fragile (as ServiceManager isn't
// thread safe). // thread safe).
void LoadServiceOnUIThread(ServiceManager* manager, void LoadOnUIThread(ServiceManager* manager,
const GURL& url, const GURL& url,
ScopedMessagePipeHandle* shell_handle); ScopedMessagePipeHandle* shell_handle);
void OnServiceErrorOnUIThread(ServiceManager* manager, const GURL& url); void OnServiceErrorOnUIThread(ServiceManager* manager, const GURL& url);
void ShutdownOnUIThread(); void ShutdownOnUIThread();
......
...@@ -20,10 +20,13 @@ ViewManagerLoader::ViewManagerLoader() { ...@@ -20,10 +20,13 @@ ViewManagerLoader::ViewManagerLoader() {
ViewManagerLoader::~ViewManagerLoader() { ViewManagerLoader::~ViewManagerLoader() {
} }
void ViewManagerLoader::LoadService( void ViewManagerLoader::Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) {
ScopedMessagePipeHandle shell_handle) { ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
if (!shell_handle.is_valid())
return;
// TODO(sky): this needs some sort of authentication as well as making sure // TODO(sky): this needs some sort of authentication as well as making sure
// we only ever have one active at a time. // we only ever have one active at a time.
scoped_ptr<ApplicationImpl> app( scoped_ptr<ApplicationImpl> app(
......
...@@ -30,10 +30,9 @@ class ViewManagerLoader ...@@ -30,10 +30,9 @@ class ViewManagerLoader
private: private:
// ServiceLoader overrides: // ServiceLoader overrides:
virtual void LoadService( virtual void Load(ServiceManager* manager,
ServiceManager* manager, const GURL& url,
const GURL& url, scoped_refptr<LoadCallbacks> callbacks) OVERRIDE;
ScopedMessagePipeHandle shell_handle) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager, virtual void OnServiceError(ServiceManager* manager,
const GURL& url) OVERRIDE; const GURL& url) OVERRIDE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment