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

Side by Side Diff: src/trusted/plugin/file_downloader.cc

Issue 7799028: Remove src/trusted/plugin (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: fix gyp file for necessary -I Created 9 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « src/trusted/plugin/file_downloader.h ('k') | src/trusted/plugin/manifest.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Native Client 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 "native_client/src/trusted/plugin/file_downloader.h"
6
7 #include <stdio.h>
8 #include <string>
9
10 #include "native_client/src/include/portability_io.h"
11 #include "native_client/src/shared/platform/nacl_check.h"
12 #include "native_client/src/shared/platform/nacl_time.h"
13 #include "native_client/src/trusted/plugin/plugin.h"
14 #include "native_client/src/trusted/plugin/utility.h"
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/c/ppb_file_io.h"
17 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
18 #include "ppapi/cpp/file_io.h"
19 #include "ppapi/cpp/file_ref.h"
20 #include "ppapi/cpp/url_request_info.h"
21 #include "ppapi/cpp/url_response_info.h"
22
23 namespace {
24 const int32_t kExtensionUrlRequestStatusOk = 200;
25 const int32_t kDataUriRequestStatusOk = 0;
26 }
27
28 namespace plugin {
29
30 void FileDownloader::Initialize(Plugin* instance) {
31 PLUGIN_PRINTF(("FileDownloader::FileDownloader (this=%p)\n",
32 static_cast<void*>(this)));
33 CHECK(instance != NULL);
34 CHECK(instance_ == NULL); // Can only initialize once.
35 instance_ = instance;
36 callback_factory_.Initialize(this);
37 file_io_trusted_interface_ = static_cast<const PPB_FileIOTrusted*>(
38 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE));
39 }
40
41
42 bool FileDownloader::Open(const nacl::string& url,
43 DownloadFlags flags,
44 const pp::CompletionCallback& callback) {
45 PLUGIN_PRINTF(("FileDownloader::Open (url=%s)\n", url.c_str()));
46 if (callback.pp_completion_callback().func == NULL ||
47 instance_ == NULL ||
48 file_io_trusted_interface_ == NULL)
49 return false;
50
51 CHECK(instance_ != NULL);
52 open_time_ = NaClGetTimeOfDayMicroseconds();
53 url_to_open_ = url;
54 url_ = url;
55 file_open_notify_callback_ = callback;
56 flags_ = flags;
57 buffer_.clear();
58 pp::Module* module = pp::Module::Get();
59 pp::URLRequestInfo url_request(instance_);
60
61 do {
62 // Reset the url loader and file reader.
63 // Note that we have the only reference to the underlying objects, so
64 // this will implicitly close any pending IO and destroy them.
65 url_loader_ = pp::URLLoader(instance_);
66 url_scheme_ = instance_->GetUrlScheme(url);
67 bool grant_universal_access = false;
68 if (url_scheme_ == SCHEME_CHROME_EXTENSION) {
69 if (instance_->IsForeignMIMEType()) {
70 // This NEXE is being used as a content type handler rather than
71 // directly by an HTML document. In that case, the NEXE runs in the
72 // security context of the content it is rendering and the NEXE itself
73 // appears to be a cross-origin resource stored in a Chrome extension.
74 // We request universal access during this load so that we can read the
75 // NEXE.
76 grant_universal_access = true;
77 }
78 } else if (url_scheme_ == SCHEME_DATA) {
79 // TODO(elijahtaylor) Remove this when data URIs can be read without
80 // universal access.
81 if (streaming_to_buffer()) {
82 grant_universal_access = true;
83 } else {
84 // Open is to invoke a callback on success or failure. Schedule
85 // it asynchronously to follow PPAPI's convention and avoid reentrancy.
86 pp::Core* core = pp::Module::Get()->core();
87 core->CallOnMainThread(0, callback, PP_ERROR_NOACCESS);
88 PLUGIN_PRINTF(("FileDownloader::Open (pp_error=PP_ERROR_NOACCESS)\n"));
89 return true;
90 }
91 }
92
93 if (grant_universal_access) {
94 const PPB_URLLoaderTrusted* url_loaded_trusted =
95 static_cast<const PPB_URLLoaderTrusted*>(
96 module->GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE));
97 if (url_loaded_trusted != NULL)
98 url_loaded_trusted->GrantUniversalAccess(url_loader_.pp_resource());
99 }
100
101 // Prepare the url request.
102 url_request.SetURL(url_);
103
104 if (streaming_to_file()) {
105 file_reader_ = pp::FileIO(instance_);
106 url_request.SetStreamToFile(true);
107 }
108 } while (0);
109
110 void (FileDownloader::*start_notify)(int32_t);
111 if (streaming_to_file())
112 start_notify = &FileDownloader::URLLoadStartNotify;
113 else
114 start_notify = &FileDownloader::URLBufferStartNotify;
115
116 // Request asynchronous download of the url providing an on-load callback.
117 // As long as this step is guaranteed to be asynchronous, we can call
118 // synchronously all other internal callbacks that eventually result in the
119 // invocation of the user callback. The user code will not be reentered.
120 pp::CompletionCallback onload_callback =
121 callback_factory_.NewRequiredCallback(start_notify);
122 int32_t pp_error = url_loader_.Open(url_request, onload_callback);
123 PLUGIN_PRINTF(("FileDownloader::Open (pp_error=%"NACL_PRId32")\n", pp_error));
124 CHECK(pp_error == PP_OK_COMPLETIONPENDING);
125 return true;
126 }
127
128 int32_t FileDownloader::GetPOSIXFileDescriptor() {
129 if (!streaming_to_file()) {
130 return NACL_NO_FILE_DESC;
131 }
132 // Use the trusted interface to get the file descriptor.
133 if (file_io_trusted_interface_ == NULL) {
134 return NACL_NO_FILE_DESC;
135 }
136 int32_t file_desc = file_io_trusted_interface_->GetOSFileDescriptor(
137 file_reader_.pp_resource());
138
139
140 #if NACL_WINDOWS
141 // Convert the Windows HANDLE from Pepper to a POSIX file descriptor.
142 int32_t posix_desc = _open_osfhandle(file_desc, _O_RDWR | _O_BINARY);
143 if (posix_desc == -1) {
144 // Close the Windows HANDLE if it can't be converted.
145 CloseHandle(reinterpret_cast<HANDLE>(file_desc));
146 return NACL_NO_FILE_DESC;
147 }
148 file_desc = posix_desc;
149 #endif
150
151 return file_desc;
152 }
153
154 int64_t FileDownloader::TimeSinceOpenMilliseconds() const {
155 int64_t now = NaClGetTimeOfDayMicroseconds();
156 // If Open() wasn't called or we somehow return an earlier time now, just
157 // return the 0 rather than worse nonsense values.
158 if (open_time_ < 0 || now < open_time_)
159 return 0;
160 return (now - open_time_) / NACL_MICROS_PER_MILLI;
161 }
162
163 bool FileDownloader::InitialResponseIsValid(int32_t pp_error) {
164 if (pp_error != PP_OK) { // Url loading failed.
165 file_open_notify_callback_.Run(pp_error);
166 return false;
167 }
168
169 // Process the response, validating the headers to confirm successful loading.
170 pp::URLResponseInfo url_response(url_loader_.GetResponseInfo());
171 if (url_response.is_null()) {
172 PLUGIN_PRINTF((
173 "FileDownloader::InitialResponseIsValid (url_response=NULL)\n"));
174 file_open_notify_callback_.Run(PP_ERROR_FAILED);
175 return false;
176 }
177 // Note that URLs in the chrome-extension scheme produce different error
178 // codes than other schemes. This is because chrome-extension URLs are
179 // really a special kind of file scheme, and therefore do not produce HTTP
180 // status codes.
181 pp::Var full_url = url_response.GetURL();
182 if (!full_url.is_string()) {
183 PLUGIN_PRINTF((
184 "FileDownloader::InitialResponseIsValid (url is not a string)\n"));
185 file_open_notify_callback_.Run(PP_ERROR_FAILED);
186 return false;
187 }
188 bool status_ok = false;
189 int32_t status_code = url_response.GetStatusCode();
190 switch (url_scheme_) {
191 case SCHEME_CHROME_EXTENSION:
192 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (chrome-extension "
193 "response status_code=%"NACL_PRId32")\n", status_code));
194 status_ok = (status_code == kExtensionUrlRequestStatusOk);
195 break;
196 case SCHEME_DATA:
197 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (data URI "
198 "response status_code=%"NACL_PRId32")\n", status_code));
199 status_ok = (status_code == kDataUriRequestStatusOk);
200 break;
201 case SCHEME_OTHER:
202 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (HTTP response "
203 "status_code=%"NACL_PRId32")\n", status_code));
204 status_ok = (status_code == NACL_HTTP_STATUS_OK);
205 break;
206 }
207
208 if (!status_ok) {
209 file_open_notify_callback_.Run(PP_ERROR_FAILED);
210 return false;
211 }
212
213 return true;
214 }
215
216 void FileDownloader::URLLoadStartNotify(int32_t pp_error) {
217 PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (pp_error=%"
218 NACL_PRId32")\n", pp_error));
219
220 if (!InitialResponseIsValid(pp_error))
221 return;
222 // Finish streaming the body providing an optional callback.
223 pp::CompletionCallback onload_callback =
224 callback_factory_.NewOptionalCallback(
225 &FileDownloader::URLLoadFinishNotify);
226 pp_error = url_loader_.FinishStreamingToFile(onload_callback);
227 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING);
228 PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (async_notify_ok=%d)\n",
229 async_notify_ok));
230 if (!async_notify_ok) {
231 // Call manually to free allocated memory and report errors. This calls
232 // |file_open_notify_callback_| with |pp_error| as the parameter.
233 onload_callback.Run(pp_error);
234 }
235 }
236
237 void FileDownloader::URLLoadFinishNotify(int32_t pp_error) {
238 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (pp_error=%"
239 NACL_PRId32")\n", pp_error));
240 if (pp_error != PP_OK) { // Streaming failed.
241 file_open_notify_callback_.Run(pp_error);
242 return;
243 }
244
245 pp::URLResponseInfo url_response(url_loader_.GetResponseInfo());
246 // Validated on load.
247 CHECK(url_response.GetStatusCode() == NACL_HTTP_STATUS_OK ||
248 url_response.GetStatusCode() == kExtensionUrlRequestStatusOk);
249
250 // Record the full url from the response.
251 pp::Var full_url = url_response.GetURL();
252 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (full_url=%s)\n",
253 full_url.DebugString().c_str()));
254 if (!full_url.is_string()) {
255 file_open_notify_callback_.Run(PP_ERROR_FAILED);
256 return;
257 }
258 url_ = full_url.AsString();
259
260 // The file is now fully downloaded.
261 pp::FileRef file(url_response.GetBodyAsFileRef());
262 if (file.is_null()) {
263 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (file=NULL)\n"));
264 file_open_notify_callback_.Run(PP_ERROR_FAILED);
265 return;
266 }
267
268 // Open the file providing an optional callback.
269 pp::CompletionCallback onopen_callback =
270 callback_factory_.NewOptionalCallback(&FileDownloader::FileOpenNotify);
271 pp_error = file_reader_.Open(file, PP_FILEOPENFLAG_READ, onopen_callback);
272 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING);
273 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (async_notify_ok=%d)\n",
274 async_notify_ok));
275 if (!async_notify_ok) {
276 // Call manually to free allocated memory and report errors. This calls
277 // |file_open_notify_callback_| with |pp_error| as the parameter.
278 onopen_callback.Run(pp_error);
279 }
280 }
281
282 void FileDownloader::URLBufferStartNotify(int32_t pp_error) {
283 PLUGIN_PRINTF(("FileDownloader::URLBufferStartNotify (pp_error=%"
284 NACL_PRId32")\n", pp_error));
285
286 if (!InitialResponseIsValid(pp_error))
287 return;
288 // Finish streaming the body asynchronously providing a callback.
289 pp::CompletionCallback onread_callback =
290 callback_factory_.NewOptionalCallback(&FileDownloader::URLReadBodyNotify);
291 pp_error = url_loader_.ReadResponseBody(temp_buffer_,
292 kTempBufferSize,
293 onread_callback);
294 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING);
295 PLUGIN_PRINTF(("FileDownloader::URLBufferStartNotify (async_notify_ok=%d)\n",
296 async_notify_ok));
297 if (!async_notify_ok) {
298 onread_callback.Run(pp_error);
299 }
300 }
301
302 void FileDownloader::URLReadBodyNotify(int32_t pp_error) {
303 PLUGIN_PRINTF(("FileDownloader::URLReadBodyNotify (pp_error=%"
304 NACL_PRId32")\n", pp_error));
305 if (pp_error < PP_OK) {
306 file_open_notify_callback_.Run(pp_error);
307 } else if (pp_error == PP_OK) {
308 FileOpenNotify(PP_OK);
309 } else {
310 buffer_.insert(buffer_.end(), temp_buffer_, temp_buffer_ + pp_error);
311 pp::CompletionCallback onread_callback =
312 callback_factory_.NewOptionalCallback(
313 &FileDownloader::URLReadBodyNotify);
314 pp_error = url_loader_.ReadResponseBody(temp_buffer_,
315 kTempBufferSize,
316 onread_callback);
317 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING);
318 if (!async_notify_ok) {
319 onread_callback.Run(pp_error);
320 }
321 }
322 }
323
324 void FileDownloader::FileOpenNotify(int32_t pp_error) {
325 PLUGIN_PRINTF(("FileDownloader::FileOpenNotify (pp_error=%"NACL_PRId32")\n",
326 pp_error));
327 file_open_notify_callback_.Run(pp_error);
328 }
329
330 bool FileDownloader::streaming_to_file() const {
331 return (flags_ & DOWNLOAD_TO_BUFFER) == 0;
332 }
333
334 bool FileDownloader::streaming_to_buffer() const {
335 return (flags_ & DOWNLOAD_TO_BUFFER) == 1;
336 }
337
338 } // namespace plugin
OLDNEW
« no previous file with comments | « src/trusted/plugin/file_downloader.h ('k') | src/trusted/plugin/manifest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698