| Index: services/sky_packaged_app_viewer/content_handler_impl.cc
|
| diff --git a/services/sky_packaged_app_viewer/content_handler_impl.cc b/services/sky_packaged_app_viewer/content_handler_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b53eac819d562edb23f9a110df11df02c94df69c
|
| --- /dev/null
|
| +++ b/services/sky_packaged_app_viewer/content_handler_impl.cc
|
| @@ -0,0 +1,211 @@
|
| +// Copyright 2015 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 "services/sky_packaged_app_viewer/content_handler_impl.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/files/scoped_temp_dir.h"
|
| +#include "base/memory/scoped_vector.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "mojo/common/data_pipe_utils.h"
|
| +#include "mojo/public/cpp/application/connect.h"
|
| +#include "mojo/public/cpp/bindings/strong_binding.h"
|
| +#include "mojo/public/cpp/utility/run_loop.h"
|
| +#include "mojo/services/http_server/public/cpp/http_server_util.h"
|
| +#include "mojo/services/http_server/public/interfaces/http_server.mojom.h"
|
| +#include "mojo/services/http_server/public/interfaces/http_server_factory.mojom.h"
|
| +#include "sky/viewer/sky_loader.h"
|
| +#include "third_party/zlib/google/zip_reader.h"
|
| +
|
| +namespace sky_packaged_app_viewer {
|
| +
|
| +class PendingRequest {
|
| + public:
|
| + PendingRequest(mojo::InterfaceRequest<mojo::ServiceProvider> services,
|
| + mojo::ServiceProviderPtr exposed_services)
|
| + : services(services.Pass()), exposed_services(exposed_services.Pass()) {}
|
| +
|
| + mojo::InterfaceRequest<mojo::ServiceProvider> services;
|
| + mojo::ServiceProviderPtr exposed_services;
|
| +};
|
| +
|
| +class HttpHandler : public http_server::HttpHandler {
|
| + public:
|
| + HttpHandler(const base::Callback<void(uint16_t)>& handler_ready_callback,
|
| + base::FilePath package_root,
|
| + http_server::HttpServerFactoryPtr http_server_factory)
|
| + : binding_(this),
|
| + handler_ready_callback_(handler_ready_callback),
|
| + package_root_(package_root) {
|
| + http_server::HttpHandlerPtr http_handler_ptr;
|
| + binding_.Bind(GetProxy(&http_handler_ptr));
|
| +
|
| + http_server_factory->CreateHttpServer(GetProxy(&http_server_).Pass(),
|
| + nullptr);
|
| + http_server_->SetHandler(
|
| + "/.*", http_handler_ptr.Pass(),
|
| + base::Bind(&HttpHandler::AddHandlerCallback, base::Unretained(this)));
|
| + }
|
| +
|
| + ~HttpHandler() override {}
|
| +
|
| + // http_server::HttpHandler:
|
| + void HandleRequest(http_server::HttpRequestPtr request,
|
| + const mojo::Callback<void(http_server::HttpResponsePtr)>&
|
| + callback) override {
|
| + std::string relative_path = request->relative_url.get().substr(1);
|
| +
|
| + // TODO(blundell): Add logic into creating sky_packaged_applications to
|
| + // make it unnecessary to strip off the "packages/" prefix, namely,
|
| + // putting all the dependent packages under "packages/".
|
| + std::string packages_prefix = "packages/";
|
| + if (!relative_path.compare(0, packages_prefix.size(), packages_prefix))
|
| + relative_path.erase(0, packages_prefix.size());
|
| +
|
| + base::FilePath entry_path = package_root_.Append(relative_path);
|
| + std::string contents;
|
| + if (!base::ReadFileToString(entry_path, &contents)) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + callback.Run(http_server::CreateHttpResponse(200, contents));
|
| + }
|
| +
|
| + void AddHandlerCallback(bool result) {
|
| + CHECK(result);
|
| + http_server_->GetPort(
|
| + base::Bind(&HttpHandler::GetPortCallback, base::Unretained(this)));
|
| + }
|
| +
|
| + void GetPortCallback(uint16_t port) { handler_ready_callback_.Run(port); }
|
| +
|
| + mojo::Binding<http_server::HttpHandler> binding_;
|
| + base::Callback<void(uint16_t)> handler_ready_callback_;
|
| + base::FilePath package_root_;
|
| + http_server::HttpServerPtr http_server_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(HttpHandler);
|
| +};
|
| +
|
| +class SkyPackagedApplication : public mojo::Application {
|
| + public:
|
| + SkyPackagedApplication(mojo::InterfaceRequest<mojo::Application> application,
|
| + mojo::URLResponsePtr response)
|
| + : binding_(this, application.Pass()),
|
| + initial_response_(response.Pass()) {}
|
| +
|
| + void Initialize(mojo::ShellPtr shell,
|
| + mojo::Array<mojo::String> args,
|
| + const mojo::String& url) override {
|
| + shell_ = shell.Pass();
|
| + sky_loader_.reset(new sky::SkyLoader(shell_.get(), mojo::URLResponsePtr()));
|
| + }
|
| +
|
| + void AcceptConnection(const mojo::String& requestor_url,
|
| + mojo::InterfaceRequest<mojo::ServiceProvider> services,
|
| + mojo::ServiceProviderPtr exposed_services,
|
| + const mojo::String& url) override {
|
| + if (local_entrypoint_url_ != "") {
|
| + DCHECK(!initial_response_);
|
| + sky_loader_->LoadApplication(
|
| + services.Pass(), exposed_services.Pass(), local_entrypoint_url_);
|
| + return;
|
| + }
|
| +
|
| + PendingRequest* request =
|
| + new PendingRequest(services.Pass(), exposed_services.Pass());
|
| + pending_requests_.push_back(request);
|
| +
|
| + if (initial_response_)
|
| + ExtractAndSetUpSkyApplication(initial_response_.Pass());
|
| + }
|
| +
|
| + void RequestQuit() override { mojo::RunLoop::current()->Quit(); }
|
| +
|
| + private:
|
| + void OnHandlerReady(uint16_t port) {
|
| + local_entrypoint_url_ =
|
| + base::StringPrintf("http://localhost:%hu/main.sky", port);
|
| + for (PendingRequest* pending_request : pending_requests_) {
|
| + sky_loader_->LoadApplication(pending_request->services.Pass(),
|
| + pending_request->exposed_services.Pass(),
|
| + local_entrypoint_url_);
|
| + }
|
| + pending_requests_.clear();
|
| + }
|
| +
|
| + void ConnectToSkyApplication(
|
| + mojo::InterfaceRequest<mojo::ServiceProvider> services,
|
| + mojo::ServiceProviderPtr exposed_services) {
|
| + sky_loader_->LoadApplication(
|
| + services.Pass(), exposed_services.Pass(), local_entrypoint_url_);
|
| + }
|
| +
|
| + void ExtractAndSetUpSkyApplication(mojo::URLResponsePtr response) {
|
| + // Extract the application.
|
| + CHECK(unpacked_app_directory_.CreateUniqueTempDir());
|
| + ExtractApplication(response.Pass());
|
| + base::FilePath package_root = unpacked_app_directory_.path();
|
| +
|
| + // Start up the http handler that will serve the application.
|
| + mojo::ServiceProviderPtr service_provider;
|
| + shell_->ConnectToApplication("mojo:http_server",
|
| + mojo::GetProxy(&service_provider), nullptr);
|
| + http_server::HttpServerFactoryPtr http_server_factory;
|
| + mojo::ConnectToService(service_provider.get(), &http_server_factory);
|
| +
|
| + http_handler_.reset(
|
| + new HttpHandler(base::Bind(&SkyPackagedApplication::OnHandlerReady,
|
| + base::Unretained(this)),
|
| + package_root, http_server_factory.Pass()));
|
| + }
|
| +
|
| + // TODO(blundell): The below two functions should be moved into a utility
|
| + // file somewhere where they can be shared by this file, the Dart content
|
| + // handler, and the Python content handler.
|
| + void ExtractApplication(mojo::URLResponsePtr response) {
|
| + zip::ZipReader reader;
|
| + const std::string input_data = CopyToString(response->body.Pass());
|
| + CHECK(reader.OpenFromString(input_data));
|
| + base::FilePath temp_dir_path = unpacked_app_directory_.path();
|
| + while (reader.HasMore()) {
|
| + CHECK(reader.OpenCurrentEntryInZip());
|
| + CHECK(reader.ExtractCurrentEntryIntoDirectory(temp_dir_path));
|
| + CHECK(reader.AdvanceToNextEntry());
|
| + }
|
| + }
|
| +
|
| + std::string CopyToString(mojo::ScopedDataPipeConsumerHandle body) {
|
| + std::string body_str;
|
| + bool result = mojo::common::BlockingCopyToString(body.Pass(), &body_str);
|
| + DCHECK(result);
|
| + return body_str;
|
| + }
|
| +
|
| + mojo::StrongBinding<mojo::Application> binding_;
|
| + scoped_ptr<HttpHandler> http_handler_;
|
| + mojo::ShellPtr shell_;
|
| + mojo::URLResponsePtr initial_response_;
|
| + ScopedVector<PendingRequest> pending_requests_;
|
| + base::ScopedTempDir unpacked_app_directory_;
|
| + scoped_ptr<sky::SkyLoader> sky_loader_;
|
| + std::string local_entrypoint_url_;
|
| +};
|
| +
|
| +ContentHandlerImpl::ContentHandlerImpl(
|
| + mojo::InterfaceRequest<mojo::ContentHandler> request)
|
| + : binding_(this, request.Pass()) {
|
| +}
|
| +
|
| +ContentHandlerImpl::~ContentHandlerImpl() {
|
| +}
|
| +
|
| +void ContentHandlerImpl::StartApplication(
|
| + mojo::InterfaceRequest<mojo::Application> application,
|
| + mojo::URLResponsePtr response) {
|
| + new SkyPackagedApplication(application.Pass(), response.Pass());
|
| +}
|
| +
|
| +} // namespace sky_packaged_app_viewer
|
|
|