| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/sky_packaged_app_viewer/content_handler_impl.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/files/scoped_temp_dir.h" |
| 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/strings/stringprintf.h" |
| 11 #include "mojo/common/data_pipe_utils.h" |
| 12 #include "mojo/public/cpp/application/connect.h" |
| 13 #include "mojo/public/cpp/bindings/strong_binding.h" |
| 14 #include "mojo/public/cpp/utility/run_loop.h" |
| 15 #include "mojo/services/http_server/public/cpp/http_server_util.h" |
| 16 #include "mojo/services/http_server/public/interfaces/http_server.mojom.h" |
| 17 #include "mojo/services/http_server/public/interfaces/http_server_factory.mojom.
h" |
| 18 #include "sky/viewer/sky_loader.h" |
| 19 #include "third_party/zlib/google/zip_reader.h" |
| 20 |
| 21 namespace sky_packaged_app_viewer { |
| 22 |
| 23 class PendingRequest { |
| 24 public: |
| 25 PendingRequest(mojo::InterfaceRequest<mojo::ServiceProvider> services, |
| 26 mojo::ServiceProviderPtr exposed_services) |
| 27 : services(services.Pass()), exposed_services(exposed_services.Pass()) {} |
| 28 |
| 29 mojo::InterfaceRequest<mojo::ServiceProvider> services; |
| 30 mojo::ServiceProviderPtr exposed_services; |
| 31 }; |
| 32 |
| 33 class HttpHandler : public http_server::HttpHandler { |
| 34 public: |
| 35 HttpHandler(const base::Callback<void(uint16_t)>& handler_ready_callback, |
| 36 base::FilePath package_root, |
| 37 http_server::HttpServerFactoryPtr http_server_factory) |
| 38 : binding_(this), |
| 39 handler_ready_callback_(handler_ready_callback), |
| 40 package_root_(package_root) { |
| 41 http_server::HttpHandlerPtr http_handler_ptr; |
| 42 binding_.Bind(GetProxy(&http_handler_ptr)); |
| 43 |
| 44 http_server_factory->CreateHttpServer(GetProxy(&http_server_).Pass(), |
| 45 nullptr); |
| 46 http_server_->SetHandler( |
| 47 "/.*", http_handler_ptr.Pass(), |
| 48 base::Bind(&HttpHandler::AddHandlerCallback, base::Unretained(this))); |
| 49 } |
| 50 |
| 51 ~HttpHandler() override {} |
| 52 |
| 53 // http_server::HttpHandler: |
| 54 void HandleRequest(http_server::HttpRequestPtr request, |
| 55 const mojo::Callback<void(http_server::HttpResponsePtr)>& |
| 56 callback) override { |
| 57 std::string relative_path = request->relative_url.get().substr(1); |
| 58 |
| 59 // TODO(blundell): Add logic into creating sky_packaged_applications to |
| 60 // make it unnecessary to strip off the "packages/" prefix, namely, |
| 61 // putting all the dependent packages under "packages/". |
| 62 std::string packages_prefix = "packages/"; |
| 63 if (!relative_path.compare(0, packages_prefix.size(), packages_prefix)) |
| 64 relative_path.erase(0, packages_prefix.size()); |
| 65 |
| 66 base::FilePath entry_path = package_root_.Append(relative_path); |
| 67 std::string contents; |
| 68 if (!base::ReadFileToString(entry_path, &contents)) { |
| 69 NOTREACHED(); |
| 70 return; |
| 71 } |
| 72 |
| 73 callback.Run(http_server::CreateHttpResponse(200, contents)); |
| 74 } |
| 75 |
| 76 void AddHandlerCallback(bool result) { |
| 77 CHECK(result); |
| 78 http_server_->GetPort( |
| 79 base::Bind(&HttpHandler::GetPortCallback, base::Unretained(this))); |
| 80 } |
| 81 |
| 82 void GetPortCallback(uint16_t port) { handler_ready_callback_.Run(port); } |
| 83 |
| 84 mojo::Binding<http_server::HttpHandler> binding_; |
| 85 base::Callback<void(uint16_t)> handler_ready_callback_; |
| 86 base::FilePath package_root_; |
| 87 http_server::HttpServerPtr http_server_; |
| 88 |
| 89 DISALLOW_COPY_AND_ASSIGN(HttpHandler); |
| 90 }; |
| 91 |
| 92 class SkyPackagedApplication : public mojo::Application { |
| 93 public: |
| 94 SkyPackagedApplication(mojo::InterfaceRequest<mojo::Application> application, |
| 95 mojo::URLResponsePtr response) |
| 96 : binding_(this, application.Pass()), |
| 97 initial_response_(response.Pass()) {} |
| 98 |
| 99 void Initialize(mojo::ShellPtr shell, |
| 100 mojo::Array<mojo::String> args, |
| 101 const mojo::String& url) override { |
| 102 shell_ = shell.Pass(); |
| 103 sky_loader_.reset(new sky::SkyLoader(shell_.get(), mojo::URLResponsePtr())); |
| 104 } |
| 105 |
| 106 void AcceptConnection(const mojo::String& requestor_url, |
| 107 mojo::InterfaceRequest<mojo::ServiceProvider> services, |
| 108 mojo::ServiceProviderPtr exposed_services, |
| 109 const mojo::String& url) override { |
| 110 if (local_entrypoint_url_ != "") { |
| 111 DCHECK(!initial_response_); |
| 112 sky_loader_->LoadApplication( |
| 113 services.Pass(), exposed_services.Pass(), local_entrypoint_url_); |
| 114 return; |
| 115 } |
| 116 |
| 117 PendingRequest* request = |
| 118 new PendingRequest(services.Pass(), exposed_services.Pass()); |
| 119 pending_requests_.push_back(request); |
| 120 |
| 121 if (initial_response_) |
| 122 ExtractAndSetUpSkyApplication(initial_response_.Pass()); |
| 123 } |
| 124 |
| 125 void RequestQuit() override { mojo::RunLoop::current()->Quit(); } |
| 126 |
| 127 private: |
| 128 void OnHandlerReady(uint16_t port) { |
| 129 local_entrypoint_url_ = |
| 130 base::StringPrintf("http://localhost:%hu/main.sky", port); |
| 131 for (PendingRequest* pending_request : pending_requests_) { |
| 132 sky_loader_->LoadApplication(pending_request->services.Pass(), |
| 133 pending_request->exposed_services.Pass(), |
| 134 local_entrypoint_url_); |
| 135 } |
| 136 pending_requests_.clear(); |
| 137 } |
| 138 |
| 139 void ConnectToSkyApplication( |
| 140 mojo::InterfaceRequest<mojo::ServiceProvider> services, |
| 141 mojo::ServiceProviderPtr exposed_services) { |
| 142 sky_loader_->LoadApplication( |
| 143 services.Pass(), exposed_services.Pass(), local_entrypoint_url_); |
| 144 } |
| 145 |
| 146 void ExtractAndSetUpSkyApplication(mojo::URLResponsePtr response) { |
| 147 // Extract the application. |
| 148 CHECK(unpacked_app_directory_.CreateUniqueTempDir()); |
| 149 ExtractApplication(response.Pass()); |
| 150 base::FilePath package_root = unpacked_app_directory_.path(); |
| 151 |
| 152 // Start up the http handler that will serve the application. |
| 153 mojo::ServiceProviderPtr service_provider; |
| 154 shell_->ConnectToApplication("mojo:http_server", |
| 155 mojo::GetProxy(&service_provider), nullptr); |
| 156 http_server::HttpServerFactoryPtr http_server_factory; |
| 157 mojo::ConnectToService(service_provider.get(), &http_server_factory); |
| 158 |
| 159 http_handler_.reset( |
| 160 new HttpHandler(base::Bind(&SkyPackagedApplication::OnHandlerReady, |
| 161 base::Unretained(this)), |
| 162 package_root, http_server_factory.Pass())); |
| 163 } |
| 164 |
| 165 // TODO(blundell): The below two functions should be moved into a utility |
| 166 // file somewhere where they can be shared by this file, the Dart content |
| 167 // handler, and the Python content handler. |
| 168 void ExtractApplication(mojo::URLResponsePtr response) { |
| 169 zip::ZipReader reader; |
| 170 const std::string input_data = CopyToString(response->body.Pass()); |
| 171 CHECK(reader.OpenFromString(input_data)); |
| 172 base::FilePath temp_dir_path = unpacked_app_directory_.path(); |
| 173 while (reader.HasMore()) { |
| 174 CHECK(reader.OpenCurrentEntryInZip()); |
| 175 CHECK(reader.ExtractCurrentEntryIntoDirectory(temp_dir_path)); |
| 176 CHECK(reader.AdvanceToNextEntry()); |
| 177 } |
| 178 } |
| 179 |
| 180 std::string CopyToString(mojo::ScopedDataPipeConsumerHandle body) { |
| 181 std::string body_str; |
| 182 bool result = mojo::common::BlockingCopyToString(body.Pass(), &body_str); |
| 183 DCHECK(result); |
| 184 return body_str; |
| 185 } |
| 186 |
| 187 mojo::StrongBinding<mojo::Application> binding_; |
| 188 scoped_ptr<HttpHandler> http_handler_; |
| 189 mojo::ShellPtr shell_; |
| 190 mojo::URLResponsePtr initial_response_; |
| 191 ScopedVector<PendingRequest> pending_requests_; |
| 192 base::ScopedTempDir unpacked_app_directory_; |
| 193 scoped_ptr<sky::SkyLoader> sky_loader_; |
| 194 std::string local_entrypoint_url_; |
| 195 }; |
| 196 |
| 197 ContentHandlerImpl::ContentHandlerImpl( |
| 198 mojo::InterfaceRequest<mojo::ContentHandler> request) |
| 199 : binding_(this, request.Pass()) { |
| 200 } |
| 201 |
| 202 ContentHandlerImpl::~ContentHandlerImpl() { |
| 203 } |
| 204 |
| 205 void ContentHandlerImpl::StartApplication( |
| 206 mojo::InterfaceRequest<mojo::Application> application, |
| 207 mojo::URLResponsePtr response) { |
| 208 new SkyPackagedApplication(application.Pass(), response.Pass()); |
| 209 } |
| 210 |
| 211 } // namespace sky_packaged_app_viewer |
| OLD | NEW |