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

Side by Side 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: Remove mime mapping 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/shell/dynamic_application_loader.h" 5 #include "mojo/shell/dynamic_application_loader.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/format_macros.h"
12 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop.h"
16 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
15 #include "mojo/common/common_type_converters.h" 18 #include "mojo/common/common_type_converters.h"
16 #include "mojo/common/data_pipe_utils.h" 19 #include "mojo/common/data_pipe_utils.h"
20 #include "mojo/public/cpp/system/data_pipe.h"
17 #include "mojo/services/public/interfaces/network/url_loader.mojom.h" 21 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
18 #include "mojo/shell/context.h" 22 #include "mojo/shell/context.h"
19 #include "mojo/shell/filename_util.h" 23 #include "mojo/shell/filename_util.h"
20 #include "mojo/shell/switches.h" 24 #include "mojo/shell/switches.h"
21 #include "url/url_util.h" 25 #include "url/url_util.h"
22 26
23 namespace mojo { 27 namespace mojo {
24 namespace shell { 28 namespace shell {
25 29
30 namespace {
31
32 void IgnoreResult(bool result) {
33 }
34
35 class LoaderResponse {
Aaron Boodman 2014/11/03 19:20:15 Is there some better way to factor this? It seems
qsr 2014/11/04 11:58:34 Not easily. But I can definitively make this class
Aaron Boodman 2014/11/04 18:05:01 Really? It seems like all the methods of this clas
qsr 2014/11/05 10:21:54 We could do this, but it would mean adding the fie
36 public:
37 explicit LoaderResponse(URLResponsePtr response)
38 : file_needs_cleanup_(true), response_(response.Pass()) {}
39 LoaderResponse(const GURL& url, base::FilePath path)
40 : file_needs_cleanup_(false), url_(url), path_(path) {}
41
42 ~LoaderResponse() {
43 if (file_needs_cleanup_ && !path_.empty())
44 base::DeleteFile(path_, false);
45 }
46
47 URLResponsePtr AsURLResponse(base::TaskRunner* task_runner) {
48 if (response_ || path_.empty())
49 return response_.Pass();
50 URLResponsePtr response(URLResponse::New());
51 response->url = String::From(url_);
52 DataPipe data_pipe;
53 response->body = data_pipe.consumer_handle.Pass();
54 int64 file_size;
55 if (base::GetFileSize(path_, &file_size)) {
56 response->headers = Array<String>(1);
57 response->headers[0] =
58 base::StringPrintf("Content-Length: %" PRId64, file_size);
59 }
60 common::CopyFromFile(path_,
61 data_pipe.producer_handle.Pass(),
62 task_runner,
63 base::Bind(&IgnoreResult));
Aaron Boodman 2014/11/04 18:05:00 I think you can also do this? base::Callback<void
qsr 2014/11/05 10:21:54 Not really. See the comment in base/task_runner_ut
64 return response.Pass();
65 }
66
67 void AsPath(base::TaskRunner* task_runner,
68 base::Callback<void(const base::FilePath&, bool)> callback) {
69 if (!path_.empty() || !response_) {
70 callback.Run(path_, base::PathExists(path_));
71 return;
72 }
73 base::CreateTemporaryFile(&path_);
74 common::CopyToFile(response_->body.Pass(),
75 path_,
76 task_runner,
77 base::Bind(callback, path_));
78 }
79
80 std::string MimeType() {
81 if (response_)
82 return response_->mime_type;
83 return "";
84 }
85
86 std::string Url() {
87 if (response_)
88 return response_->url;
89 return String::From(url_);
90 }
91
92 private:
93 bool file_needs_cleanup_;
94 URLResponsePtr response_;
95 GURL url_;
96 base::FilePath path_;
97 };
98
99 } // namespace
100
26 // Encapsulates loading and running one individual application. 101 // Encapsulates loading and running one individual application.
27 // 102 //
28 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must 103 // Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
29 // ensure that all the parameters passed to Loader subclasses stay valid through 104 // ensure that all the parameters passed to Loader subclasses stay valid through
30 // Loader's lifetime. 105 // Loader's lifetime.
31 // 106 //
32 // Async operations are done with WeakPtr to protect against 107 // Async operations are done with WeakPtr to protect against
33 // DynamicApplicationLoader going away (and taking all the Loaders with it) 108 // DynamicApplicationLoader going away (and taking all the Loaders with it)
34 // while the async operation is outstanding. 109 // while the async operation is outstanding.
35 class DynamicApplicationLoader::Loader { 110 class DynamicApplicationLoader::Loader {
36 public: 111 public:
37 Loader(Context* context, 112 Loader(Context* context,
113 MimeTypeToURLMap* mime_type_to_url,
38 DynamicServiceRunnerFactory* runner_factory, 114 DynamicServiceRunnerFactory* runner_factory,
39 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, 115 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
40 const LoaderCompleteCallback& loader_complete_callback) 116 const LoaderCompleteCallback& loader_complete_callback)
41 : load_callbacks_(load_callbacks), 117 : load_callbacks_(load_callbacks),
42 loader_complete_callback_(loader_complete_callback), 118 loader_complete_callback_(loader_complete_callback),
43 context_(context), 119 context_(context),
120 mime_type_to_url_(mime_type_to_url),
44 runner_factory_(runner_factory), 121 runner_factory_(runner_factory),
45 weak_ptr_factory_(this) {} 122 weak_ptr_factory_(this) {}
46 123
47 virtual ~Loader() {} 124 virtual ~Loader() {}
48 125
49 protected: 126 protected:
50 void RunLibrary(const base::FilePath& path, bool path_exists) { 127 void RunLibrary(const base::FilePath& path, bool path_exists) {
51 ScopedMessagePipeHandle shell_handle = 128 ScopedMessagePipeHandle shell_handle =
52 load_callbacks_->RegisterApplication(); 129 load_callbacks_->RegisterApplication();
53 if (!shell_handle.is_valid()) { 130 if (!shell_handle.is_valid()) {
(...skipping 10 matching lines...) Expand all
64 141
65 runner_ = runner_factory_->Create(context_); 142 runner_ = runner_factory_->Create(context_);
66 runner_->Start( 143 runner_->Start(
67 path, 144 path,
68 shell_handle.Pass(), 145 shell_handle.Pass(),
69 base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr())); 146 base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr()));
70 } 147 }
71 148
72 void LoaderComplete() { loader_complete_callback_.Run(this); } 149 void LoaderComplete() { loader_complete_callback_.Run(this); }
73 150
151 void OnResponse(scoped_ptr<LoaderResponse> response) {
152 MimeTypeToURLMap::iterator iter =
153 mime_type_to_url_->find(response->MimeType());
154 if (iter != mime_type_to_url_->end()) {
155 load_callbacks_->LoadWithContentHandler(
156 iter->second,
157 response->AsURLResponse(context_->task_runners()->blocking_pool()));
158 return;
159 }
160
161 LOG(INFO) << "Failed to find content handler for " << response->Url()
162 << " (mimetype: " << response->MimeType() << ")" << std::endl
163 << "Attempting to load as native library instead...";
164
165 // TODO(aa): Santify check that the thing we got looks vaguely like a mojo
166 // application. That could either mean looking for the platform-specific dll
167 // header, or looking for some specific mojo signature prepended to the
168 // library.
169
170 response->AsPath(
171 context_->task_runners()->blocking_pool(),
172 base::Bind(&Loader::RunLibrary, weak_ptr_factory_.GetWeakPtr()));
173 }
174
74 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_; 175 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
75 LoaderCompleteCallback loader_complete_callback_; 176 LoaderCompleteCallback loader_complete_callback_;
76 Context* context_; 177 Context* context_;
178 MimeTypeToURLMap* mime_type_to_url_;
77 179
78 private: 180 private:
79 DynamicServiceRunnerFactory* runner_factory_; 181 DynamicServiceRunnerFactory* runner_factory_;
80 scoped_ptr<DynamicServiceRunner> runner_; 182 scoped_ptr<DynamicServiceRunner> runner_;
81 base::WeakPtrFactory<Loader> weak_ptr_factory_; 183 base::WeakPtrFactory<Loader> weak_ptr_factory_;
82 }; 184 };
83 185
84 // A loader for local files. 186 // A loader for local files.
85 class DynamicApplicationLoader::LocalLoader : public Loader { 187 class DynamicApplicationLoader::LocalLoader : public Loader {
86 public: 188 public:
87 LocalLoader(const GURL& url, 189 LocalLoader(const GURL& url,
88 Context* context, 190 Context* context,
191 MimeTypeToURLMap* mime_type_to_url,
89 DynamicServiceRunnerFactory* runner_factory, 192 DynamicServiceRunnerFactory* runner_factory,
90 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, 193 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
91 const LoaderCompleteCallback& loader_complete_callback) 194 const LoaderCompleteCallback& loader_complete_callback)
92 : Loader(context, 195 : Loader(context,
196 mime_type_to_url,
93 runner_factory, 197 runner_factory,
94 load_callbacks, 198 load_callbacks,
95 loader_complete_callback), 199 loader_complete_callback) {
96 weak_ptr_factory_(this) {
97 DCHECK(url.SchemeIsFile()); 200 DCHECK(url.SchemeIsFile());
98 url::RawCanonOutputW<1024> output; 201 url::RawCanonOutputW<1024> output;
99 url::DecodeURLEscapeSequences( 202 url::DecodeURLEscapeSequences(
100 url.path().data(), static_cast<int>(url.path().length()), &output); 203 url.path().data(), static_cast<int>(url.path().length()), &output);
101 base::string16 decoded_path = 204 base::string16 decoded_path =
102 base::string16(output.data(), output.length()); 205 base::string16(output.data(), output.length());
103 #if defined(OS_WIN) 206 #if defined(OS_WIN)
104 base::FilePath path(decoded_path); 207 base::FilePath path(decoded_path);
105 #else 208 #else
106 base::FilePath path(base::UTF16ToUTF8(decoded_path)); 209 base::FilePath path(base::UTF16ToUTF8(decoded_path));
107 #endif 210 #endif
108 211
109 // Async for consistency with network case. 212 OnResponse(make_scoped_ptr(new LoaderResponse(url, path)));
110 base::MessageLoop::current()->PostTask(
111 FROM_HERE,
112 base::Bind(&LocalLoader::RunLibrary,
113 weak_ptr_factory_.GetWeakPtr(),
114 path,
115 base::PathExists(path)));
116 } 213 }
117 214
118 ~LocalLoader() override {} 215 ~LocalLoader() override {}
119
120 private:
121 base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
122 }; 216 };
123 217
124 // A loader for network files. 218 // A loader for network files.
125 class DynamicApplicationLoader::NetworkLoader : public Loader { 219 class DynamicApplicationLoader::NetworkLoader : public Loader {
126 public: 220 public:
127 NetworkLoader(const GURL& url, 221 NetworkLoader(const GURL& url,
128 MimeTypeToURLMap* mime_type_to_url, 222 MimeTypeToURLMap* mime_type_to_url,
129 Context* context, 223 Context* context,
130 DynamicServiceRunnerFactory* runner_factory, 224 DynamicServiceRunnerFactory* runner_factory,
131 NetworkService* network_service, 225 NetworkService* network_service,
132 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, 226 scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
133 const LoaderCompleteCallback& loader_complete_callback) 227 const LoaderCompleteCallback& loader_complete_callback)
134 : Loader(context, 228 : Loader(context,
229 mime_type_to_url,
135 runner_factory, 230 runner_factory,
136 load_callbacks, 231 load_callbacks,
137 loader_complete_callback), 232 loader_complete_callback),
138 mime_type_to_url_(mime_type_to_url),
139 weak_ptr_factory_(this) { 233 weak_ptr_factory_(this) {
140 URLRequestPtr request(URLRequest::New()); 234 URLRequestPtr request(URLRequest::New());
141 request->url = String::From(url); 235 request->url = String::From(url);
142 request->auto_follow_redirects = true; 236 request->auto_follow_redirects = true;
143 237
144 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 238 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
145 switches::kDisableCache)) { 239 switches::kDisableCache)) {
146 request->bypass_cache = true; 240 request->bypass_cache = true;
147 } 241 }
148 242
149 network_service->CreateURLLoader(GetProxy(&url_loader_)); 243 network_service->CreateURLLoader(GetProxy(&url_loader_));
150 url_loader_->Start(request.Pass(), 244 url_loader_->Start(request.Pass(),
151 base::Bind(&NetworkLoader::OnLoadComplete, 245 base::Bind(&NetworkLoader::OnLoadComplete,
152 weak_ptr_factory_.GetWeakPtr())); 246 weak_ptr_factory_.GetWeakPtr()));
153 } 247 }
154 248
155 ~NetworkLoader() override {
156 if (!file_.empty())
157 base::DeleteFile(file_, false);
158 }
159
160 private: 249 private:
161 void OnLoadComplete(URLResponsePtr response) { 250 void OnLoadComplete(URLResponsePtr response) {
162 if (response->error) { 251 if (response->error) {
163 LOG(ERROR) << "Error (" << response->error->code << ": " 252 LOG(ERROR) << "Error (" << response->error->code << ": "
164 << response->error->description << ") while fetching " 253 << response->error->description << ") while fetching "
165 << response->url; 254 << response->url;
166 LoaderComplete(); 255 LoaderComplete();
167 return; 256 return;
168 } 257 }
169 258
170 MimeTypeToURLMap::iterator iter = 259 OnResponse(make_scoped_ptr(new LoaderResponse(response.Pass())));
171 mime_type_to_url_->find(response->mime_type);
172 if (iter != mime_type_to_url_->end()) {
173 load_callbacks_->LoadWithContentHandler(iter->second, response.Pass());
174 return;
175 }
176
177 LOG(INFO) << "Failed to find content handler for " << response->url
178 << " (mimetype: " << response->url << ")" << std::endl
179 << "Attempting to load as native library instead...";
180
181 // TODO(aa): Santify check that the thing we got looks vaguely like a mojo
182 // application. That could either mean looking for the platform-specific dll
183 // header, or looking for some specific mojo signature prepended to the
184 // library.
185
186 base::CreateTemporaryFile(&file_);
187 common::CopyToFile(
188 response->body.Pass(),
189 file_,
190 context_->task_runners()->blocking_pool(),
191 base::Bind(
192 &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_));
193 } 260 }
194 261
195 MimeTypeToURLMap* mime_type_to_url_;
196 URLLoaderPtr url_loader_; 262 URLLoaderPtr url_loader_;
197 base::FilePath file_;
198 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_; 263 base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
199 }; 264 };
200 265
201 DynamicApplicationLoader::DynamicApplicationLoader( 266 DynamicApplicationLoader::DynamicApplicationLoader(
202 Context* context, 267 Context* context,
203 scoped_ptr<DynamicServiceRunnerFactory> runner_factory) 268 scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
204 : context_(context), 269 : context_(context),
205 runner_factory_(runner_factory.Pass()), 270 runner_factory_(runner_factory.Pass()),
206 271
207 // Unretained() is correct here because DynamicApplicationLoader owns the 272 // Unretained() is correct here because DynamicApplicationLoader owns the
(...skipping 19 matching lines...) Expand all
227 GURL resolved_url; 292 GURL resolved_url;
228 if (url.SchemeIs("mojo")) { 293 if (url.SchemeIs("mojo")) {
229 resolved_url = context_->mojo_url_resolver()->Resolve(url); 294 resolved_url = context_->mojo_url_resolver()->Resolve(url);
230 } else { 295 } else {
231 resolved_url = url; 296 resolved_url = url;
232 } 297 }
233 298
234 if (resolved_url.SchemeIsFile()) { 299 if (resolved_url.SchemeIsFile()) {
235 loaders_.push_back(new LocalLoader(resolved_url, 300 loaders_.push_back(new LocalLoader(resolved_url,
236 context_, 301 context_,
302 &mime_type_to_url_,
237 runner_factory_.get(), 303 runner_factory_.get(),
238 load_callbacks, 304 load_callbacks,
239 loader_complete_callback_)); 305 loader_complete_callback_));
240 return; 306 return;
241 } 307 }
242 308
243 if (!network_service_) { 309 if (!network_service_) {
244 context_->application_manager()->ConnectToService( 310 context_->application_manager()->ConnectToService(
245 GURL("mojo:network_service"), &network_service_); 311 GURL("mojo:network_service"), &network_service_);
246 } 312 }
(...skipping 12 matching lines...) Expand all
259 // TODO(darin): What should we do about service errors? This implies that 325 // TODO(darin): What should we do about service errors? This implies that
260 // the app closed its handle to the service manager. Maybe we don't care? 326 // the app closed its handle to the service manager. Maybe we don't care?
261 } 327 }
262 328
263 void DynamicApplicationLoader::LoaderComplete(Loader* loader) { 329 void DynamicApplicationLoader::LoaderComplete(Loader* loader) {
264 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); 330 loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader));
265 } 331 }
266 332
267 } // namespace shell 333 } // namespace shell
268 } // namespace mojo 334 } // namespace mojo
OLDNEW
« mojo/common/data_pipe_utils.cc ('K') | « mojo/common/data_pipe_utils.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698