| Index: mojo/shell/dynamic_service_loader.cc
|
| diff --git a/mojo/shell/dynamic_service_loader.cc b/mojo/shell/dynamic_service_loader.cc
|
| index b249c3cff31c70769160eac16d71ace46df80426..815d2e875c8fa4519c9058a177e65919166b6526 100644
|
| --- a/mojo/shell/dynamic_service_loader.cc
|
| +++ b/mojo/shell/dynamic_service_loader.cc
|
| @@ -4,83 +4,137 @@
|
|
|
| #include "mojo/shell/dynamic_service_loader.h"
|
|
|
| -#include "base/location.h"
|
| +#include "base/bind.h"
|
| +#include "base/command_line.h"
|
| +#include "base/file_util.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "mojo/common/data_pipe_utils.h"
|
| +#include "mojo/services/public/interfaces/network/url_loader.mojom.h"
|
| #include "mojo/shell/context.h"
|
| #include "mojo/shell/keep_alive.h"
|
| +#include "mojo/shell/switches.h"
|
| +#include "net/base/filename_util.h"
|
|
|
| namespace mojo {
|
| namespace shell {
|
| -
|
| namespace {
|
|
|
| -std::string MakeSharedLibraryName(const std::string& file_name) {
|
| -#if defined(OS_WIN)
|
| - return file_name + ".dll";
|
| -#elif defined(OS_LINUX)
|
| - return "lib" + file_name + ".so";
|
| -#elif defined(OS_MACOSX)
|
| - return "lib" + file_name + ".dylib";
|
| -#else
|
| - NOTREACHED() << "dynamic loading of services not supported";
|
| - return std::string();
|
| -#endif
|
| -}
|
| +class Loader {
|
| + public:
|
| + explicit Loader(scoped_ptr<DynamicServiceRunner> runner)
|
| + : runner_(runner.Pass()) {
|
| + }
|
|
|
| -} // namespace
|
| + virtual void Start(const GURL& url,
|
| + ScopedMessagePipeHandle service_handle,
|
| + Context* context) = 0;
|
|
|
| -class DynamicServiceLoader::LoadContext : public mojo::shell::Loader::Delegate {
|
| - public:
|
| - LoadContext(DynamicServiceLoader* loader,
|
| - const GURL& url,
|
| - ScopedMessagePipeHandle service_handle,
|
| - scoped_ptr<DynamicServiceRunner> runner)
|
| - : loader_(loader),
|
| - url_(url),
|
| - service_handle_(service_handle.Pass()),
|
| - runner_(runner.Pass()),
|
| - keep_alive_(loader->context_) {
|
| - GURL url_to_load;
|
| -
|
| - if (url.SchemeIs("mojo")) {
|
| - std::string lib = MakeSharedLibraryName(url.ExtractFileName());
|
| - url_to_load = GURL(loader->context_->mojo_origin() + "/" + lib);
|
| + 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 {
|
| - url_to_load = url;
|
| + 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()) {
|
| + }
|
|
|
| - request_ = loader_->context_->loader()->Load(url_to_load, this);
|
| + virtual void Start(const GURL& url,
|
| + ScopedMessagePipeHandle service_handle,
|
| + Context* context) OVERRIDE {
|
| + base::FilePath path;
|
| + net::FileURLToFilePath(url, &path);
|
| +
|
| + // TODO(darin): Check if the given file path exists.
|
| +
|
| + // Complete asynchronously for consistency with NetworkServiceLoader.
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&Loader::StartService,
|
| + base::Unretained(this),
|
| + path,
|
| + base::Passed(&service_handle),
|
| + true));
|
| }
|
| +};
|
|
|
| - virtual ~LoadContext() {
|
| +// For loading services via the network stack.
|
| +class NetworkLoader : public Loader, public URLLoaderClient {
|
| + public:
|
| + explicit NetworkLoader(scoped_ptr<DynamicServiceRunner> runner,
|
| + NetworkService* network_service)
|
| + : Loader(runner.Pass()) {
|
| + network_service->CreateURLLoader(Get(&url_loader_));
|
| + url_loader_.set_client(this);
|
| + }
|
| +
|
| + virtual void Start(const GURL& url,
|
| + ScopedMessagePipeHandle service_handle,
|
| + Context* context) OVERRIDE {
|
| + service_handle_ = service_handle.Pass();
|
| +
|
| + URLRequestPtr request(URLRequest::New());
|
| + request->url = url.spec();
|
| + request->follow_redirects = true;
|
| +
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kDisableCache)) {
|
| + request->bypass_cache = true;
|
| + }
|
| +
|
| + DataPipe data_pipe;
|
| + url_loader_->Start(request.Pass(), data_pipe.producer_handle.Pass());
|
| +
|
| + base::CreateTemporaryFile(&file_);
|
| + common::CopyToFile(data_pipe.consumer_handle.Pass(),
|
| + file_,
|
| + context->task_runners()->blocking_pool(),
|
| + base::Bind(&Loader::StartService,
|
| + base::Unretained(this),
|
| + file_,
|
| + base::Passed(&service_handle_)));
|
| }
|
|
|
| private:
|
| - // |Loader::Delegate| method:
|
| - virtual void DidCompleteLoad(const GURL& app_url,
|
| - const base::FilePath& app_path,
|
| - const std::string* mime_type) OVERRIDE {
|
| - DVLOG(2) << "Completed load of " << app_url << " (" << url_ << ") to "
|
| - << app_path.value();
|
| - DCHECK(loader_->context_->task_runners()->ui_runner()->
|
| - BelongsToCurrentThread());
|
| -
|
| - runner_->Start(
|
| - app_path,
|
| - service_handle_.Pass(),
|
| - base::Bind(&DynamicServiceLoader::AppCompleted,
|
| - base::Unretained(loader_), url_));
|
| + // URLLoaderClient methods:
|
| + virtual void OnReceivedRedirect(URLResponsePtr response,
|
| + const String& new_url,
|
| + const String& new_method) OVERRIDE {
|
| + // TODO(darin): Handle redirects properly!
|
| }
|
| + virtual void OnReceivedResponse(URLResponsePtr response) {}
|
| + virtual void OnReceivedError(NetworkErrorPtr error) {}
|
| + virtual void OnReceivedEndOfResponseBody() {}
|
|
|
| - DynamicServiceLoader* const loader_;
|
| - const GURL url_;
|
| - scoped_ptr<mojo::shell::Loader::Job> request_;
|
| + NetworkServicePtr network_service_;
|
| + URLLoaderPtr url_loader_;
|
| ScopedMessagePipeHandle service_handle_;
|
| - scoped_ptr<DynamicServiceRunner> runner_;
|
| - KeepAlive keep_alive_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(LoadContext);
|
| + base::FilePath file_;
|
| };
|
|
|
| +} // namespace
|
| +
|
| DynamicServiceLoader::DynamicServiceLoader(
|
| Context* context,
|
| scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
|
| @@ -89,32 +143,38 @@ DynamicServiceLoader::DynamicServiceLoader(
|
| }
|
|
|
| DynamicServiceLoader::~DynamicServiceLoader() {
|
| - DCHECK(url_to_load_context_.empty());
|
| }
|
|
|
| void DynamicServiceLoader::LoadService(ServiceManager* manager,
|
| const GURL& url,
|
| ScopedMessagePipeHandle service_handle) {
|
| - DCHECK(url_to_load_context_.find(url) == url_to_load_context_.end());
|
| - url_to_load_context_[url] = new LoadContext(
|
| - this, url, service_handle.Pass(), runner_factory_->Create(context_));
|
| + scoped_ptr<DynamicServiceRunner> runner = runner_factory_->Create(context_);
|
| +
|
| + GURL resolved_url;
|
| + if (url.SchemeIs("mojo")) {
|
| + resolved_url = context_->mojo_url_resolver()->Resolve(url);
|
| + } else {
|
| + resolved_url = url;
|
| + }
|
| +
|
| + Loader* loader;
|
| + if (resolved_url.SchemeIsFile()) {
|
| + loader = new LocalLoader(runner.Pass());
|
| + } else {
|
| + if (!network_service_.get()) {
|
| + context_->service_manager()->ConnectTo(GURL("mojo:mojo_network_service"),
|
| + &network_service_,
|
| + GURL());
|
| + }
|
| + loader = new NetworkLoader(runner.Pass(), network_service_.get());
|
| + }
|
| + loader->Start(resolved_url, service_handle.Pass(), context_);
|
| }
|
|
|
| void DynamicServiceLoader::OnServiceError(ServiceManager* manager,
|
| const GURL& url) {
|
| -}
|
| -
|
| -void DynamicServiceLoader::AppCompleted(const GURL& url) {
|
| - DCHECK(context_->task_runners()->ui_runner()->BelongsToCurrentThread());
|
| - DVLOG(2) << "App completed (url: " << url << ")";
|
| -
|
| - LoadContextMap::iterator it = url_to_load_context_.find(url);
|
| - DCHECK(it != url_to_load_context_.end()) << url;
|
| -
|
| - LoadContext* doomed = it->second;
|
| - url_to_load_context_.erase(it);
|
| -
|
| - delete doomed;
|
| + // TODO(darin): What should we do about service errors? This implies that
|
| + // the app closed its handle to the service manager. Maybe we don't care?
|
| }
|
|
|
| } // namespace shell
|
|
|