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

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: Follow review 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/common/data_pipe_utils_unittest.cc ('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 e2e07da90572a4535352a68f4a760974cf2ac3ab..6a1d2cf901cc07a5bac570dca3f6787f083abd77 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,6 +29,16 @@
namespace mojo {
namespace shell {
+namespace {
+
+static const char kMojoMagic[] = "#!mojo:";
+static const size_t kMaxShebangLength = 2048;
+
+void IgnoreResult(bool result) {
+}
+
+} // namespace
+
// Encapsulates loading and running one individual application.
//
// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
@@ -36,48 +50,104 @@ namespace shell {
// while the async operation is outstanding.
class DynamicApplicationLoader::Loader {
public:
- Loader(Context* context,
+ Loader(MimeTypeToURLMap* mime_type_to_url,
+ 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),
+ mime_type_to_url_(mime_type_to_url),
runner_factory_(runner_factory),
weak_ptr_factory_(this) {}
virtual ~Loader() {}
protected:
+ 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;
+
+ virtual std::string MimeType() = 0;
+
+ virtual bool HasMojoMagic() = 0;
+
+ virtual bool PeekFirstLine(std::string* line) = 0;
+
+ void Load() {
+ // If the response begins with a #!mojo:<content-handler-url>, use it.
+ GURL url;
+ std::string shebang;
+ if (PeekContentHandler(&shebang, &url)) {
+ load_callbacks_->LoadWithContentHandler(
+ url, AsURLResponse(context_->task_runners()->blocking_pool(),
+ shebang.size()));
+ return;
+ }
+
+ MimeTypeToURLMap::iterator iter = mime_type_to_url_->find(MimeType());
+ if (iter != mime_type_to_url_->end()) {
+ load_callbacks_->LoadWithContentHandler(
+ iter->second,
+ AsURLResponse(context_->task_runners()->blocking_pool(), 0));
+ return;
+ }
+
+ // TODO(aa): Sanity check that the thing we got looks vaguely like a mojo
+ // application. That could either mean looking for the platform-specific dll
+ // header, or looking for some specific mojo signature prepended to the
+ // library.
+
+ AsPath(context_->task_runners()->blocking_pool(),
+ base::Bind(&Loader::RunLibrary, weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void ReportComplete() { loader_complete_callback_.Run(this); }
+
+ private:
+ bool PeekContentHandler(std::string* mojo_shebang,
+ 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;
+ }
+
void RunLibrary(const base::FilePath& path, bool path_exists) {
ScopedMessagePipeHandle shell_handle =
load_callbacks_->RegisterApplication();
if (!shell_handle.is_valid()) {
- LoaderComplete();
+ ReportComplete();
return;
}
if (!path_exists) {
LOG(ERROR) << "Library not started because library path '" << path.value()
<< "' does not exist.";
- LoaderComplete();
+ ReportComplete();
return;
}
runner_ = runner_factory_->Create(context_);
runner_->Start(
- path,
- shell_handle.Pass(),
- base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr()));
+ path, shell_handle.Pass(),
+ base::Bind(&Loader::ReportComplete, weak_ptr_factory_.GetWeakPtr()));
}
- void LoaderComplete() { loader_complete_callback_.Run(this); }
-
scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
LoaderCompleteCallback loader_complete_callback_;
Context* context_;
-
- private:
+ MimeTypeToURLMap* mime_type_to_url_;
DynamicServiceRunnerFactory* runner_factory_;
scoped_ptr<DynamicServiceRunner> runner_;
base::WeakPtrFactory<Loader> weak_ptr_factory_;
@@ -87,15 +157,23 @@ class DynamicApplicationLoader::Loader {
class DynamicApplicationLoader::LocalLoader : public Loader {
public:
LocalLoader(const GURL& url,
+ MimeTypeToURLMap* mime_type_to_url,
Context* context,
DynamicServiceRunnerFactory* runner_factory,
scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
const LoaderCompleteCallback& loader_complete_callback)
- : Loader(context,
+ : Loader(mime_type_to_url,
+ context,
runner_factory,
load_callbacks,
loader_complete_callback),
- weak_ptr_factory_(this) {
+ url_(url),
+ path_(UrlToFile(url)) {
+ Load();
+ }
+
+ private:
+ static base::FilePath UrlToFile(const GURL& url) {
DCHECK(url.SchemeIsFile());
url::RawCanonOutputW<1024> output;
url::DecodeURLEscapeSequences(
@@ -108,38 +186,128 @@ class DynamicApplicationLoader::LocalLoader : public Loader {
#else
base::FilePath path(base::UTF16ToUTF8(decoded_path));
#endif
+ return path;
+ }
+
+ 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 {
// Async for consistency with network case.
base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&LocalLoader::RunLibrary,
- weak_ptr_factory_.GetWeakPtr(),
- path,
- base::PathExists(path)));
+ FROM_HERE, base::Bind(callback, path_, base::PathExists(path_)));
}
- ~LocalLoader() override {}
+ std::string MimeType() override { return ""; }
- private:
- base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
+ bool HasMojoMagic() override {
+ std::string magic;
+ ReadFileToString(path_, &magic, strlen(kMojoMagic));
+ return magic == kMojoMagic;
+ }
+
+ 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;
+ }
+
+ GURL url_;
+ base::FilePath path_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalLoader);
};
// A loader for network files.
class DynamicApplicationLoader::NetworkLoader : public Loader {
public:
NetworkLoader(const GURL& url,
+ NetworkService* network_service,
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,
+ : Loader(mime_type_to_url,
+ context,
runner_factory,
load_callbacks,
loader_complete_callback),
- mime_type_to_url_(mime_type_to_url),
weak_ptr_factory_(this) {
+ StartNetworkRequest(url, network_service);
+ }
+
+ ~NetworkLoader() override {
+ if (!path_.empty())
+ base::DeleteFile(path_, false);
+ }
+
+ private:
+ // TODO(hansmuller): Revisit this when a real peek operation is available.
+ static const MojoDeadline kPeekTimeout = MOJO_DEADLINE_INDEFINITE;
+
+ 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();
+ }
+
+ 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_));
+ }
+
+ std::string MimeType() override {
+ DCHECK(response_);
+ return response_->mime_type;
+ }
+
+ bool HasMojoMagic() override {
+ std::string magic;
+ return BlockingPeekNBytes(response_->body.get(), &magic, strlen(kMojoMagic),
+ kPeekTimeout) &&
+ magic == kMojoMagic;
+ }
+
+ bool PeekFirstLine(std::string* line) override {
+ return BlockingPeekLine(response_->body.get(), line, kMaxShebangLength,
+ kPeekTimeout);
+ }
+
+ void StartNetworkRequest(const GURL& url, NetworkService* network_service) {
URLRequestPtr request(URLRequest::New());
request->url = String::From(url);
request->auto_follow_redirects = true;
@@ -155,89 +323,26 @@ class DynamicApplicationLoader::NetworkLoader : public Loader {
weak_ptr_factory_.GetWeakPtr()));
}
- ~NetworkLoader() override {
- if (!file_.empty())
- base::DeleteFile(file_, false);
- }
-
- 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;
-
- 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;
- }
- }
- return false;
- }
-
void OnLoadComplete(URLResponsePtr response) {
if (response->error) {
LOG(ERROR) << "Error (" << response->error->code << ": "
<< response->error->description << ") while fetching "
<< response->url;
- LoaderComplete();
+ ReportComplete();
return;
}
-
- // If the response begins with a #!mojo:<content-handler-url>, use it.
- {
- 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;
- }
- }
- }
-
- MimeTypeToURLMap::iterator iter =
- mime_type_to_url_->find(response->mime_type);
- if (iter != mime_type_to_url_->end()) {
- load_callbacks_->LoadWithContentHandler(iter->second, response.Pass());
- return;
- }
-
- // TODO(aa): Sanity check that the thing we got looks vaguely like a mojo
- // application. That could either mean looking for the platform-specific dll
- // header, or looking for some specific mojo signature prepended to the
- // library.
-
- base::CreateTemporaryFile(&file_);
- common::CopyToFile(
- response->body.Pass(),
- file_,
- context_->task_runners()->blocking_pool(),
- base::Bind(
- &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_));
+ response_ = response.Pass();
+ Load();
}
- MimeTypeToURLMap* mime_type_to_url_;
URLLoaderPtr url_loader_;
- base::FilePath file_;
+ URLResponsePtr response_;
+ base::FilePath path_;
base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkLoader);
};
+
DynamicApplicationLoader::DynamicApplicationLoader(
Context* context,
scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
@@ -265,10 +370,8 @@ void DynamicApplicationLoader::Load(
const GURL& url,
scoped_refptr<LoadCallbacks> load_callbacks) {
if (url.SchemeIsFile()) {
- loaders_.push_back(new LocalLoader(url,
- context_,
- runner_factory_.get(),
- load_callbacks,
+ loaders_.push_back(new LocalLoader(url, &mime_type_to_url_, context_,
+ runner_factory_.get(), load_callbacks,
loader_complete_callback_));
return;
}
@@ -278,13 +381,9 @@ void DynamicApplicationLoader::Load(
GURL("mojo:network_service"), &network_service_);
}
- loaders_.push_back(new NetworkLoader(url,
- &mime_type_to_url_,
- context_,
- runner_factory_.get(),
- network_service_.get(),
- load_callbacks,
- loader_complete_callback_));
+ loaders_.push_back(new NetworkLoader(
+ url, network_service_.get(), &mime_type_to_url_, context_,
+ runner_factory_.get(), load_callbacks, loader_complete_callback_));
}
void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager,
« no previous file with comments | « mojo/common/data_pipe_utils_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698