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

Side by Side Diff: services/sky_packaged_app_viewer/content_handler_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698