Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2304)

Unified Diff: mojo/shell/dynamic_application_loader.cc

Issue 694303002: Allow local file to run though content handler. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Fix constants. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/shell/dynamic_application_loader.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/shell/dynamic_application_loader.cc
diff --git a/mojo/shell/dynamic_application_loader.cc b/mojo/shell/dynamic_application_loader.cc
index 3f5eaba0ae60ca2f2e9c84aa56ee7526adbe11eb..4c7aa1eee9489121cacfe71bb28010a251517a4d 100644
--- a/mojo/shell/dynamic_application_loader.cc
+++ b/mojo/shell/dynamic_application_loader.cc
@@ -8,13 +8,17 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/common/common_type_converters.h"
#include "mojo/common/data_pipe_utils.h"
+#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/services/public/interfaces/network/url_loader.mojom.h"
#include "mojo/shell/context.h"
#include "mojo/shell/data_pipe_peek.h"
@@ -25,77 +29,182 @@
namespace mojo {
namespace shell {
-// Encapsulates loading and running one individual application.
-//
-// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
-// ensure that all the parameters passed to Loader subclasses stay valid through
-// Loader's lifetime.
-//
-// Async operations are done with WeakPtr to protect against
-// DynamicApplicationLoader going away (and taking all the Loaders with it)
-// while the async operation is outstanding.
-class DynamicApplicationLoader::Loader {
+namespace {
+
+static const char kMojoMagic[] = "#!mojo:";
+static const size_t kMaxShebangLength = 2048;
+
+void IgnoreResult(bool result) {
+}
+
+// A request to load a given URL.
+class LoaderRequest {
public:
- Loader(Context* context,
- DynamicServiceRunnerFactory* runner_factory,
- scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
- const LoaderCompleteCallback& loader_complete_callback)
- : load_callbacks_(load_callbacks),
- loader_complete_callback_(loader_complete_callback),
- context_(context),
- runner_factory_(runner_factory),
- weak_ptr_factory_(this) {}
+ virtual ~LoaderRequest() {}
- virtual ~Loader() {}
+ virtual URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
+ uint32_t skip) = 0;
+
+ virtual void AsPath(
+ base::TaskRunner* task_runner,
+ base::Callback<void(const base::FilePath&, bool)> callback) = 0;
+
+ bool PeekContentHandler(std::string* mojo_shebang,
Aaron Boodman 2014/11/07 08:56:27 I would prefer this function in loader, and make L
+ GURL* mojo_content_handler_url) {
+ std::string shebang;
+ if (HasMojoMagic() && PeekFirstLine(&shebang)) {
+ GURL url(shebang.substr(2, std::string::npos));
+ if (url.is_valid()) {
+ *mojo_shebang = shebang;
+ *mojo_content_handler_url = url;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual std::string MimeType() = 0;
protected:
- void RunLibrary(const base::FilePath& path, bool path_exists) {
- ScopedMessagePipeHandle shell_handle =
- load_callbacks_->RegisterApplication();
- if (!shell_handle.is_valid()) {
- LoaderComplete();
- return;
+ virtual bool HasMojoMagic() = 0;
+ virtual bool PeekFirstLine(std::string* line) = 0;
+};
+
+// A request to load a remote URL.
+class NetworkLoaderRequest : public LoaderRequest {
+ public:
+ NetworkLoaderRequest(const GURL& url,
+ NetworkService* network_service,
+ const base::Callback<void(bool)>& completion_callback)
+ : completion_callback_(completion_callback), weak_ptr_factory_(this) {
+ Load(url, network_service);
+ }
+
+ ~NetworkLoaderRequest() override {
+ if (!path_.empty())
+ base::DeleteFile(path_, false);
+ }
+
+ URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
+ uint32_t skip) override {
+ if (skip != 0) {
+ MojoResult result = ReadDataRaw(
+ response_->body.get(), nullptr, &skip,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE | MOJO_READ_DATA_FLAG_DISCARD);
+ DCHECK_EQ(result, MOJO_RESULT_OK);
}
+ return response_.Pass();
+ }
- if (!path_exists) {
- LOG(ERROR) << "Library not started because library path '" << path.value()
- << "' does not exist.";
- LoaderComplete();
+ void AsPath(
+ base::TaskRunner* task_runner,
+ base::Callback<void(const base::FilePath&, bool)> callback) override {
+ if (!path_.empty() || !response_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, path_, base::PathExists(path_)));
return;
}
+ base::CreateTemporaryFile(&path_);
+ common::CopyToFile(response_->body.Pass(), path_, task_runner,
+ base::Bind(callback, path_));
+ }
- runner_ = runner_factory_->Create(context_);
- runner_->Start(
- path,
- shell_handle.Pass(),
- base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr()));
+ std::string MimeType() override {
+ DCHECK(response_);
+ return response_->mime_type;
}
- void LoaderComplete() { loader_complete_callback_.Run(this); }
+ private:
+ // TODO(hansmuller): Revisit this when a real peek operation is available.
+ static const MojoDeadline kPeekTimeout = MOJO_DEADLINE_INDEFINITE;
- scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
- LoaderCompleteCallback loader_complete_callback_;
- Context* context_;
+ bool HasMojoMagic() override {
+ std::string magic;
+ return BlockingPeekNBytes(response_->body.get(), &magic, strlen(kMojoMagic),
+ kPeekTimeout) &&
+ magic == kMojoMagic;
+ }
- private:
- DynamicServiceRunnerFactory* runner_factory_;
- scoped_ptr<DynamicServiceRunner> runner_;
- base::WeakPtrFactory<Loader> weak_ptr_factory_;
+ bool PeekFirstLine(std::string* line) override {
+ return BlockingPeekLine(response_->body.get(), line, kMaxShebangLength,
+ kPeekTimeout);
+ }
+
+ void Load(const GURL& url, NetworkService* network_service) {
+ 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;
+ }
+
+ network_service->CreateURLLoader(GetProxy(&url_loader_));
+ url_loader_->Start(request.Pass(),
+ base::Bind(&NetworkLoaderRequest::OnLoadComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void OnLoadComplete(URLResponsePtr response) {
+ if (response->error) {
+ LOG(ERROR) << "Error (" << response->error->code << ": "
+ << response->error->description << ") while fetching "
+ << response->url;
+ completion_callback_.Run(false);
+ return;
+ }
+ response_ = response.Pass();
+ completion_callback_.Run(true);
+ }
+
+ base::Callback<void(bool)> completion_callback_;
+ URLLoaderPtr url_loader_;
+ URLResponsePtr response_;
+ base::FilePath path_;
+ base::WeakPtrFactory<NetworkLoaderRequest> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkLoaderRequest);
};
-// A loader for local files.
-class DynamicApplicationLoader::LocalLoader : public Loader {
+// A request to load a file URL.
+class LocalLoaderRequest : public LoaderRequest {
public:
- LocalLoader(const GURL& url,
- Context* context,
- DynamicServiceRunnerFactory* runner_factory,
- scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
- const LoaderCompleteCallback& loader_complete_callback)
- : Loader(context,
- runner_factory,
- load_callbacks,
- loader_complete_callback),
- weak_ptr_factory_(this) {
+ LocalLoaderRequest(const GURL& url,
+ const base::Callback<void(bool)>& completion_callback)
+ : url_(url), path_(UrlToFile(url)) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(completion_callback, true));
+ }
+
+ URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
+ uint32_t skip) override {
+ URLResponsePtr response(URLResponse::New());
+ response->url = String::From(url_);
+ DataPipe data_pipe;
+ response->body = data_pipe.consumer_handle.Pass();
+ int64 file_size;
+ if (base::GetFileSize(path_, &file_size)) {
+ response->headers = Array<String>(1);
+ response->headers[0] =
+ base::StringPrintf("Content-Length: %" PRId64, file_size);
+ }
+ common::CopyFromFile(path_, data_pipe.producer_handle.Pass(), skip,
+ task_runner, base::Bind(&IgnoreResult));
+ return response.Pass();
+ }
+
+ void AsPath(
+ base::TaskRunner* task_runner,
+ base::Callback<void(const base::FilePath&, bool)> callback) override {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, path_, base::PathExists(path_)));
+ }
+
+ std::string MimeType() override { return ""; }
+
+ private:
+ static base::FilePath UrlToFile(const GURL& url) {
DCHECK(url.SchemeIsFile());
url::RawCanonOutputW<1024> output;
url::DecodeURLEscapeSequences(
@@ -108,88 +217,89 @@ class DynamicApplicationLoader::LocalLoader : public Loader {
#else
base::FilePath path(base::UTF16ToUTF8(decoded_path));
#endif
+ return path;
+ }
- // Async for consistency with network case.
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&LocalLoader::RunLibrary,
- weak_ptr_factory_.GetWeakPtr(),
- path,
- base::PathExists(path)));
+ bool HasMojoMagic() override {
+ std::string magic;
+ ReadFileToString(path_, &magic, strlen(kMojoMagic));
+ return magic == kMojoMagic;
}
- ~LocalLoader() override {}
+ bool PeekFirstLine(std::string* line) override {
+ std::string start_of_file;
+ ReadFileToString(path_, &start_of_file, kMaxShebangLength);
+ size_t return_position = start_of_file.find('\n');
+ if (return_position == std::string::npos)
+ return false;
+ *line = start_of_file.substr(0, return_position + 1);
+ return true;
+ }
- private:
- base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
+ GURL url_;
+ base::FilePath path_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalLoaderRequest);
};
-// A loader for network files.
-class DynamicApplicationLoader::NetworkLoader : public Loader {
+} // namespace
+
+// Encapsulates loading and running one individual application.
+//
+// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
+// ensure that all the parameters passed to Loader subclasses stay valid through
+// Loader's lifetime.
+//
+// Async operations are done with WeakPtr to protect against
+// DynamicApplicationLoader going away (and taking all the Loaders with it)
+// while the async operation is outstanding.
+class DynamicApplicationLoader::Loader {
public:
- NetworkLoader(const GURL& url,
- MimeTypeToURLMap* mime_type_to_url,
- Context* context,
- DynamicServiceRunnerFactory* runner_factory,
- NetworkService* network_service,
- scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
- const LoaderCompleteCallback& loader_complete_callback)
- : Loader(context,
- runner_factory,
- load_callbacks,
- loader_complete_callback),
+ Loader(const GURL& url,
+ MimeTypeToURLMap* mime_type_to_url,
+ Context* context,
+ DynamicServiceRunnerFactory* runner_factory,
+ NetworkServicePtr* network_service,
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
+ const LoaderCompleteCallback& loader_complete_callback)
+ : load_callbacks_(load_callbacks),
+ loader_complete_callback_(loader_complete_callback),
+ context_(context),
mime_type_to_url_(mime_type_to_url),
+ runner_factory_(runner_factory),
+ network_service_(network_service),
weak_ptr_factory_(this) {
- 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;
- }
-
- network_service->CreateURLLoader(GetProxy(&url_loader_));
- url_loader_->Start(request.Pass(),
- base::Bind(&NetworkLoader::OnLoadComplete,
- weak_ptr_factory_.GetWeakPtr()));
+ Load(url, network_service);
}
- ~NetworkLoader() override {
- if (!file_.empty())
- base::DeleteFile(file_, false);
- }
+ virtual ~Loader() {}
private:
- bool PeekContentHandler(DataPipeConsumerHandle source,
- std::string* mojo_shebang,
- GURL* mojo_content_handler_url)
- {
- const char* kMojoMagic = "#!mojo:";
- // TODO(hansmuller): Revisit this when a real peek operation is available.
- const MojoDeadline kPeekTimeout = MOJO_DEADLINE_INDEFINITE;
- const size_t kMaxShebangLength = 2048;
+ void RunLibrary(const base::FilePath& path, bool path_exists) {
+ ScopedMessagePipeHandle shell_handle =
+ load_callbacks_->RegisterApplication();
+ if (!shell_handle.is_valid()) {
+ LoaderComplete();
+ return;
+ }
- std::string magic;
- std::string shebang;
- if (BlockingPeekNBytes(source, &magic, strlen(kMojoMagic), kPeekTimeout) &&
- magic == kMojoMagic &&
- BlockingPeekLine(source, &shebang, kMaxShebangLength, kPeekTimeout)) {
- GURL url(shebang.substr(2, std::string::npos));
- if (url.is_valid()) {
- *mojo_shebang = shebang;
- *mojo_content_handler_url = url;
- return true;
- }
+ if (!path_exists) {
+ LOG(ERROR) << "Library not started because library path '" << path.value()
+ << "' does not exist.";
+ LoaderComplete();
+ return;
}
- return false;
+
+ runner_ = runner_factory_->Create(context_);
+ runner_->Start(
+ path, shell_handle.Pass(),
+ base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr()));
}
- void OnLoadComplete(URLResponsePtr response) {
- if (response->error) {
- LOG(ERROR) << "Error (" << response->error->code << ": "
- << response->error->description << ") while fetching "
- << response->url;
+ void LoaderComplete() { loader_complete_callback_.Run(this); }
+
+ void OnResponse(bool success) {
+ if (!success) {
LoaderComplete();
return;
}
@@ -198,24 +308,21 @@ class DynamicApplicationLoader::NetworkLoader : public Loader {
{
GURL url;
std::string shebang;
- if (PeekContentHandler(response->body.get(), &shebang, &url)) {
- uint32_t num_skip_bytes = shebang.size();
- if (ReadDataRaw(response->body.get(),
- nullptr,
- &num_skip_bytes,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE |
- MOJO_READ_DATA_FLAG_DISCARD) ==
- MOJO_RESULT_OK) {
- load_callbacks_->LoadWithContentHandler(url, response.Pass());
- return;
- }
+ if (request_->PeekContentHandler(&shebang, &url)) {
+ load_callbacks_->LoadWithContentHandler(
+ url,
+ request_->AsURLResponse(context_->task_runners()->blocking_pool(),
+ shebang.size()));
+ return;
}
}
MimeTypeToURLMap::iterator iter =
- mime_type_to_url_->find(response->mime_type);
+ mime_type_to_url_->find(request_->MimeType());
if (iter != mime_type_to_url_->end()) {
- load_callbacks_->LoadWithContentHandler(iter->second, response.Pass());
+ load_callbacks_->LoadWithContentHandler(
+ iter->second, request_->AsURLResponse(
+ context_->task_runners()->blocking_pool(), 0));
return;
}
@@ -224,20 +331,49 @@ class DynamicApplicationLoader::NetworkLoader : public Loader {
// header, or looking for some specific mojo signature prepended to the
// library.
- base::CreateTemporaryFile(&file_);
- common::CopyToFile(
- response->body.Pass(),
- file_,
+ request_->AsPath(
context_->task_runners()->blocking_pool(),
- base::Bind(
- &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_));
+ base::Bind(&Loader::RunLibrary, weak_ptr_factory_.GetWeakPtr()));
}
+ void Load(const GURL& url, NetworkServicePtr* network_service) {
Aaron Boodman 2014/11/07 08:56:27 second param never used.
+ GURL resolved_url;
+ if (url.SchemeIs("mojo")) {
+ resolved_url = context_->mojo_url_resolver()->Resolve(url);
+ } else {
+ resolved_url = url;
+ }
+
+ if (resolved_url.SchemeIsFile()) {
+ request_.reset(new LocalLoaderRequest(
+ resolved_url,
+ base::Bind(&DynamicApplicationLoader::Loader::OnResponse,
+ weak_ptr_factory_.GetWeakPtr())));
+ return;
+ }
+
+ if (!network_service_->get()) {
Aaron Boodman 2014/11/07 08:56:27 Put this back in DAL::Load() so that we share one
+ context_->application_manager()->ConnectToService(
+ GURL("mojo:network_service"), network_service_);
Aaron Boodman 2014/11/07 08:56:27 network_service_ is a pointer, so I guess this pip
qsr 2014/11/07 09:33:22 I mixed 2 things here, sorry. network_service_ sho
+ }
+
+ request_.reset(new NetworkLoaderRequest(
+ resolved_url, network_service_->get(),
+ base::Bind(&DynamicApplicationLoader::Loader::OnResponse,
+ weak_ptr_factory_.GetWeakPtr())));
+ }
+
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
+ LoaderCompleteCallback loader_complete_callback_;
+ Context* context_;
MimeTypeToURLMap* mime_type_to_url_;
- URLLoaderPtr url_loader_;
- base::FilePath file_;
- base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
+ DynamicServiceRunnerFactory* runner_factory_;
+ NetworkServicePtr* network_service_;
+ scoped_ptr<DynamicServiceRunner> runner_;
+ scoped_ptr<LoaderRequest> request_;
+ base::WeakPtrFactory<Loader> weak_ptr_factory_;
};
+
DynamicApplicationLoader::DynamicApplicationLoader(
Context* context,
scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
@@ -264,34 +400,9 @@ void DynamicApplicationLoader::Load(
ApplicationManager* manager,
const GURL& url,
scoped_refptr<LoadCallbacks> load_callbacks) {
- GURL resolved_url;
- if (url.SchemeIs("mojo")) {
- resolved_url = context_->mojo_url_resolver()->Resolve(url);
- } else {
- resolved_url = url;
- }
-
- if (resolved_url.SchemeIsFile()) {
- loaders_.push_back(new LocalLoader(resolved_url,
- context_,
- runner_factory_.get(),
- load_callbacks,
- loader_complete_callback_));
- return;
- }
-
- if (!network_service_) {
- context_->application_manager()->ConnectToService(
- GURL("mojo:network_service"), &network_service_);
- }
-
- loaders_.push_back(new NetworkLoader(resolved_url,
- &mime_type_to_url_,
- context_,
- runner_factory_.get(),
- network_service_.get(),
- load_callbacks,
- loader_complete_callback_));
+ loaders_.push_back(new Loader(url, &mime_type_to_url_, context_,
+ runner_factory_.get(), &network_service_,
Aaron Boodman 2014/11/07 08:56:27 this is always null.
+ load_callbacks, loader_complete_callback_));
}
void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager,
« no previous file with comments | « mojo/shell/dynamic_application_loader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698