| Index: mojo/python/content_handler/content_handler_main.cc
|
| diff --git a/mojo/python/content_handler/content_handler_main.cc b/mojo/python/content_handler/content_handler_main.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3bc09c17f983cab1a0a4e7e6a586f25c49d4336b
|
| --- /dev/null
|
| +++ b/mojo/python/content_handler/content_handler_main.cc
|
| @@ -0,0 +1,177 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <python2.7/Python.h>
|
| +#include <dlfcn.h>
|
| +
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/scoped_temp_dir.h"
|
| +#include "base/i18n/icu_util.h"
|
| +#include "mojo/application/application_runner_chromium.h"
|
| +#include "mojo/application/content_handler_factory.h"
|
| +#include "mojo/common/common_type_converters.h"
|
| +#include "mojo/common/data_pipe_utils.h"
|
| +#include "mojo/public/c/system/main.h"
|
| +#include "mojo/public/cpp/application/application_delegate.h"
|
| +#include "mojo/public/cpp/application/application_impl.h"
|
| +#include "mojo/public/cpp/application/interface_factory_impl.h"
|
| +#include "mojo/public/python/src/common.h"
|
| +#include "third_party/zlib/google/zip_reader.h"
|
| +
|
| +char kMojoSystem[] = "mojo_system";
|
| +char kMojoSystemImpl[] = "mojo_system_impl";
|
| +char kMojoMain[] = "MojoMain";
|
| +
|
| +extern "C" {
|
| + void initmojo_system();
|
| + void initmojo_system_impl();
|
| +}
|
| +
|
| +namespace mojo {
|
| +namespace python {
|
| +
|
| +class PythonContentHandler : public ApplicationDelegate,
|
| + public ContentHandlerFactory::Delegate {
|
| + public:
|
| + PythonContentHandler() : content_handler_factory_(this) {}
|
| +
|
| + private:
|
| + // Overridden from ApplicationDelegate:
|
| + bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
|
| + connection->AddService(&content_handler_factory_);
|
| + return true;
|
| + }
|
| +
|
| + // Extracts the target application into a temporary directory. This directory
|
| + // is deleted at the end of the life of the PythonContentHandler object.
|
| + std::unique_ptr<base::ScopedTempDir> ExtractApplication(
|
| + URLResponsePtr response) {
|
| + std::unique_ptr<base::ScopedTempDir> temp_dir(new base::ScopedTempDir);
|
| + MOJO_CHECK(temp_dir->CreateUniqueTempDir());
|
| +
|
| + zip::ZipReader reader;
|
| + const std::string input_data = CopyToString(response->body.Pass());
|
| + MOJO_DCHECK(reader.OpenFromString(input_data));
|
| + base::FilePath temp_dir_path = temp_dir->path();
|
| + while (reader.HasMore()) {
|
| + MOJO_DCHECK(reader.OpenCurrentEntryInZip());
|
| + MOJO_DCHECK(reader.ExtractCurrentEntryIntoDirectory(temp_dir_path));
|
| + MOJO_DCHECK(reader.AdvanceToNextEntry());
|
| + }
|
| + return temp_dir;
|
| + }
|
| +
|
| + // Sets up the Python interpreter and loads mojo system modules. This method
|
| + // returns the global dictionary for the python environment that should be
|
| + // used for subsequent calls. Takes as input the path of the unpacked
|
| + // application files.
|
| + PyObject* SetupPythonEnvironment(const std::string& application_path) {
|
| + // TODO(etiennej): Build python ourselves so we don't have to rely on
|
| + // dynamically loading a system library.
|
| + dlopen("libpython2.7.so", RTLD_LAZY | RTLD_GLOBAL);
|
| +
|
| + PyImport_AppendInittab(kMojoSystemImpl, &initmojo_system_impl);
|
| + PyImport_AppendInittab(kMojoSystem, &initmojo_system);
|
| +
|
| + Py_Initialize();
|
| +
|
| + PyObject *m, *d;
|
| + m = PyImport_AddModule("__main__");
|
| + if (m == NULL)
|
| + return NULL;
|
| + d = PyModule_GetDict(m);
|
| +
|
| + // Inject the application path into the python search path so that imports
|
| + // from the application work as expected.
|
| + std::string search_path_py_command =
|
| + "import sys; sys.path.append('" + application_path + "');";
|
| + ScopedPyRef result(
|
| + PyRun_String(search_path_py_command.c_str(), Py_file_input, d, d));
|
| +
|
| + if (result == nullptr) {
|
| + LOG(ERROR) << "Error while configuring path";
|
| + PyErr_Print();
|
| + return NULL;
|
| + }
|
| +
|
| + return d;
|
| + }
|
| +
|
| + // Overridden from ContentHandlerFactory::ManagedDelegate:
|
| + void RunApplication(ShellPtr shell, URLResponsePtr response) override {
|
| + std::unique_ptr<base::ScopedTempDir> temp_dir =
|
| + ExtractApplication(response.Pass());
|
| + base::FilePath directory_path = temp_dir->path();
|
| +
|
| + PyObject* d = SetupPythonEnvironment(directory_path.value());
|
| + MOJO_DCHECK(d);
|
| +
|
| + base::FilePath entry_path = directory_path.Append("__mojo__.py");
|
| +
|
| + FILE* entry_file = base::OpenFile(entry_path, "r");
|
| + MOJO_DCHECK(entry_file);
|
| +
|
| + // Ensure that all created objects are destroyed before calling Py_Finalize.
|
| + {
|
| + // Load the __mojo__.py file into the interpreter. MojoMain hasn't run
|
| + // yet.
|
| + ScopedPyRef result(PyRun_File(entry_file, entry_path.value().c_str(),
|
| + Py_file_input, d, d));
|
| + if (result == nullptr) {
|
| + LOG(ERROR) << "Error while loading script";
|
| + PyErr_Print();
|
| + return;
|
| + }
|
| +
|
| + // Find MojoMain.
|
| + ScopedPyRef py_function(PyMapping_GetItemString(d, kMojoMain));
|
| +
|
| + if (py_function == NULL) {
|
| + LOG(ERROR) << "Locals size: " << PyMapping_Size(d);
|
| + LOG(ERROR) << "MojoMain not found";
|
| + PyErr_Print();
|
| + return;
|
| + }
|
| +
|
| + if (PyCallable_Check(py_function)) {
|
| + MojoHandle shell_handle = shell.PassMessagePipe().release().value();
|
| + ScopedPyRef py_input(PyInt_FromLong(shell_handle));
|
| + ScopedPyRef py_arguments(PyTuple_New(1));
|
| + // py_input reference is stolen by py_arguments
|
| + PyTuple_SetItem(py_arguments, 0, py_input.Release());
|
| + // Run MojoMain with shell_handle as the first and only argument.
|
| + ScopedPyRef py_output(PyObject_CallObject(py_function, py_arguments));
|
| +
|
| + if (!py_output) {
|
| + LOG(ERROR) << "Error while executing MojoMain";
|
| + PyErr_Print();
|
| + return;
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "MojoMain is not callable; it should be a function";
|
| + }
|
| + }
|
| + Py_Finalize();
|
| + }
|
| +
|
| + std::string CopyToString(ScopedDataPipeConsumerHandle body) {
|
| + std::string body_str;
|
| + bool result = common::BlockingCopyToString(body.Pass(), &body_str);
|
| + DCHECK(result);
|
| + return body_str;
|
| + }
|
| +
|
| + ContentHandlerFactory content_handler_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PythonContentHandler);
|
| +};
|
| +
|
| +} // namespace python
|
| +} // namespace mojo
|
| +
|
| +MojoResult MojoMain(MojoHandle shell_handle) {
|
| + mojo::ApplicationRunnerChromium runner(
|
| + new mojo::python::PythonContentHandler());
|
| + return runner.Run(shell_handle);
|
| +}
|
|
|