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..16ed3162e1b8e7cf3c55e7a651616d68cf91b063 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) OVERRIDE {} |
+ virtual void OnReceivedError(NetworkErrorPtr error) OVERRIDE {} |
+ virtual void OnReceivedEndOfResponseBody() OVERRIDE {} |
- 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 |