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

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: Delay running the callback in AsPath as the code doesn't support re-entrency. 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 193582b8c3344156fd3bfba615e02a5a8c38cca5..7dff74eccc1d2a00e6dbe70f2a7147bfbbfe21d3 100644
--- a/mojo/shell/dynamic_application_loader.cc
+++ b/mojo/shell/dynamic_application_loader.cc
@@ -8,12 +8,16 @@
#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/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"
@@ -24,6 +28,166 @@
namespace mojo {
namespace shell {
+namespace {
+
+void IgnoreResult(bool result) {
+}
+
+class LoaderResponse {
+ public:
+ virtual ~LoaderResponse() {}
+
+ 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,
+ 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:
+ const char* kMojoMagic = "#!mojo:";
+ const size_t kMaxShebangLength = 2048;
+
+ virtual bool HasMojoMagic() = 0;
+ virtual bool PeekFirstLine(std::string* line) = 0;
+};
+
+class NetworkLoaderResponse : public LoaderResponse {
+ public:
+ explicit NetworkLoaderResponse(URLResponsePtr response)
+ : response_(response.Pass()) {}
+
+ ~NetworkLoaderResponse() override {
+ if (!path_.empty())
+ base::DeleteFile(path_, false);
+ }
+
+ URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
+ uint32_t skip) override {
+ if (skip) {
Aaron Boodman 2014/11/06 02:46:03 I believe this will be a warning on some compilers
qsr 2014/11/06 15:30:21 Done.
+ DCHECK(ReadDataRaw(response_->body.get(),
Aaron Boodman 2014/11/06 02:46:03 This function call is going to get compiled out in
qsr 2014/11/06 15:30:21 Done.
+ nullptr,
+ &skip,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE |
+ MOJO_READ_DATA_FLAG_DISCARD) == 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;
+ }
+
+ private:
+ // TODO(hansmuller): Revisit this when a real peek operation is available.
+ const MojoDeadline kPeekTimeout = MOJO_DEADLINE_INDEFINITE;
+
+ 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);
+ }
+
+ URLResponsePtr response_;
+ base::FilePath path_;
+};
+
+class LocalLoaderResponse : public LoaderResponse {
+ public:
+ LocalLoaderResponse(const GURL& url, base::FilePath path)
+ : url_(url), path_(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 {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, path_, base::PathExists(path_)));
+ }
+
+ std::string MimeType() override { return ""; }
+
+ private:
+ GURL url_;
Aaron Boodman 2014/11/06 02:46:03 The order is: static methods, static fields, non-
Aaron Boodman 2014/11/06 07:40:33 Oops, got this slightly wrong. See here: http://g
qsr 2014/11/06 15:30:21 Done.
+ base::FilePath path_;
+
+ 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;
+ }
+};
+
+} // namespace
+
// Encapsulates loading and running one individual application.
//
// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
@@ -36,12 +200,14 @@ namespace shell {
class DynamicApplicationLoader::Loader {
public:
Loader(Context* context,
+ MimeTypeToURLMap* mime_type_to_url,
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) {}
@@ -72,9 +238,44 @@ class DynamicApplicationLoader::Loader {
void LoaderComplete() { loader_complete_callback_.Run(this); }
+ void OnResponse(scoped_ptr<LoaderResponse> response) {
+ // If the response begins with a #!mojo:<content-handler-url>, use it.
+ {
+ GURL url;
+ std::string shebang;
+ if (response->PeekContentHandler(&shebang, &url)) {
+ load_callbacks_->LoadWithContentHandler(
+ url,
+ response->AsURLResponse(context_->task_runners()->blocking_pool(),
+ shebang.size()));
+ return;
+ }
+ }
+
+ MimeTypeToURLMap::iterator iter =
+ mime_type_to_url_->find(response->MimeType());
+ if (iter != mime_type_to_url_->end()) {
+ load_callbacks_->LoadWithContentHandler(
+ iter->second,
+ response->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.
+
+ response->AsPath(
+ context_->task_runners()->blocking_pool(),
+ base::Bind(&Loader::RunLibrary, weak_ptr_factory_.GetWeakPtr()));
+ }
+
scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
LoaderCompleteCallback loader_complete_callback_;
Context* context_;
+ MimeTypeToURLMap* mime_type_to_url_;
private:
DynamicServiceRunnerFactory* runner_factory_;
@@ -87,14 +288,15 @@ class DynamicApplicationLoader::LocalLoader : public Loader {
public:
LocalLoader(const GURL& url,
Context* context,
+ MimeTypeToURLMap* mime_type_to_url,
DynamicServiceRunnerFactory* runner_factory,
scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
const LoaderCompleteCallback& loader_complete_callback)
: Loader(context,
+ mime_type_to_url,
runner_factory,
load_callbacks,
- loader_complete_callback),
- weak_ptr_factory_(this) {
+ loader_complete_callback) {
DCHECK(url.SchemeIsFile());
url::RawCanonOutputW<1024> output;
url::DecodeURLEscapeSequences(
@@ -107,19 +309,10 @@ class DynamicApplicationLoader::LocalLoader : public Loader {
base::FilePath path(base::UTF16ToUTF8(decoded_path));
#endif
- // Async for consistency with network case.
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&LocalLoader::RunLibrary,
- weak_ptr_factory_.GetWeakPtr(),
- path,
- base::PathExists(path)));
+ OnResponse(make_scoped_ptr(new LocalLoaderResponse(url, path)));
}
~LocalLoader() override {}
-
- private:
- base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
};
// A loader for network files.
@@ -133,10 +326,10 @@ class DynamicApplicationLoader::NetworkLoader : public Loader {
scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
const LoaderCompleteCallback& loader_complete_callback)
: Loader(context,
+ mime_type_to_url,
runner_factory,
load_callbacks,
loader_complete_callback),
- mime_type_to_url_(mime_type_to_url),
weak_ptr_factory_(this) {
URLRequestPtr request(URLRequest::New());
request->url = String::From(url);
@@ -153,36 +346,7 @@ 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 << ": "
@@ -192,48 +356,10 @@ class DynamicApplicationLoader::NetworkLoader : public Loader {
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_));
+ OnResponse(make_scoped_ptr(new NetworkLoaderResponse(response.Pass())));
}
- MimeTypeToURLMap* mime_type_to_url_;
URLLoaderPtr url_loader_;
- base::FilePath file_;
base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
};
DynamicApplicationLoader::DynamicApplicationLoader(
@@ -272,6 +398,7 @@ void DynamicApplicationLoader::Load(
if (resolved_url.SchemeIsFile()) {
loaders_.push_back(new LocalLoader(resolved_url,
context_,
+ &mime_type_to_url_,
runner_factory_.get(),
load_callbacks,
loader_complete_callback_));
« 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