OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "native_client/src/trusted/plugin/file_downloader.h" | 5 #include "native_client/src/trusted/plugin/file_downloader.h" |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); | 48 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); |
49 url_loader_trusted_interface_ = static_cast<const PPB_URLLoaderTrusted*>( | 49 url_loader_trusted_interface_ = static_cast<const PPB_URLLoaderTrusted*>( |
50 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE)); | 50 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE)); |
51 temp_buffer_.resize(kTempBufferSize); | 51 temp_buffer_.resize(kTempBufferSize); |
52 } | 52 } |
53 | 53 |
54 bool FileDownloader::OpenStream( | 54 bool FileDownloader::OpenStream( |
55 const nacl::string& url, | 55 const nacl::string& url, |
56 const pp::CompletionCallback& callback, | 56 const pp::CompletionCallback& callback, |
57 StreamCallbackSource* stream_callback_source) { | 57 StreamCallbackSource* stream_callback_source) { |
| 58 open_and_stream_ = false; |
58 data_stream_callback_source_ = stream_callback_source; | 59 data_stream_callback_source_ = stream_callback_source; |
59 return Open(url, DOWNLOAD_STREAM, callback, true, NULL); | 60 return Open(url, DOWNLOAD_STREAM, callback, true, NULL); |
60 } | 61 } |
61 | 62 |
62 bool FileDownloader::Open( | 63 bool FileDownloader::Open( |
63 const nacl::string& url, | 64 const nacl::string& url, |
64 DownloadMode mode, | 65 DownloadMode mode, |
65 const pp::CompletionCallback& callback, | 66 const pp::CompletionCallback& callback, |
66 bool record_progress, | 67 bool record_progress, |
67 PP_URLLoaderTrusted_StatusCallback progress_callback) { | 68 PP_URLLoaderTrusted_StatusCallback progress_callback) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 int64_t now = NaClGetTimeOfDayMicroseconds(); | 212 int64_t now = NaClGetTimeOfDayMicroseconds(); |
212 // If Open() wasn't called or we somehow return an earlier time now, just | 213 // If Open() wasn't called or we somehow return an earlier time now, just |
213 // return the 0 rather than worse nonsense values. | 214 // return the 0 rather than worse nonsense values. |
214 if (open_time_ < 0 || now < open_time_) | 215 if (open_time_ < 0 || now < open_time_) |
215 return 0; | 216 return 0; |
216 return (now - open_time_) / NACL_MICROS_PER_MILLI; | 217 return (now - open_time_) / NACL_MICROS_PER_MILLI; |
217 } | 218 } |
218 | 219 |
219 bool FileDownloader::InitialResponseIsValid(int32_t pp_error) { | 220 bool FileDownloader::InitialResponseIsValid(int32_t pp_error) { |
220 if (pp_error != PP_OK) { // Url loading failed. | 221 if (pp_error != PP_OK) { // Url loading failed. |
221 file_open_notify_callback_.Run(pp_error); | 222 file_open_notify_callback_.RunAndClear(pp_error); |
222 return false; | 223 return false; |
223 } | 224 } |
224 | 225 |
225 // Process the response, validating the headers to confirm successful loading. | 226 // Process the response, validating the headers to confirm successful loading. |
226 pp::URLResponseInfo url_response(url_loader_.GetResponseInfo()); | 227 url_response_ = url_loader_.GetResponseInfo(); |
227 if (url_response.is_null()) { | 228 if (url_response_.is_null()) { |
228 PLUGIN_PRINTF(( | 229 PLUGIN_PRINTF(( |
229 "FileDownloader::InitialResponseIsValid (url_response=NULL)\n")); | 230 "FileDownloader::InitialResponseIsValid (url_response_=NULL)\n")); |
230 file_open_notify_callback_.Run(PP_ERROR_FAILED); | 231 file_open_notify_callback_.RunAndClear(PP_ERROR_FAILED); |
231 return false; | 232 return false; |
232 } | 233 } |
233 // Note that URLs in the chrome-extension scheme produce different error | 234 |
234 // codes than other schemes. This is because chrome-extension URLs are | 235 pp::Var full_url = url_response_.GetURL(); |
235 // really a special kind of file scheme, and therefore do not produce HTTP | |
236 // status codes. | |
237 pp::Var full_url = url_response.GetURL(); | |
238 if (!full_url.is_string()) { | 236 if (!full_url.is_string()) { |
239 PLUGIN_PRINTF(( | 237 PLUGIN_PRINTF(( |
240 "FileDownloader::InitialResponseIsValid (url is not a string)\n")); | 238 "FileDownloader::InitialResponseIsValid (url is not a string)\n")); |
241 file_open_notify_callback_.Run(PP_ERROR_FAILED); | 239 file_open_notify_callback_.RunAndClear(PP_ERROR_FAILED); |
242 return false; | 240 return false; |
243 } | 241 } |
| 242 url_ = full_url.AsString(); |
| 243 |
| 244 // Note that URLs in the data-URI scheme produce different error |
| 245 // codes than other schemes. This is because data-URI are really a |
| 246 // special kind of file scheme, and therefore do not produce HTTP |
| 247 // status codes. |
244 bool status_ok = false; | 248 bool status_ok = false; |
245 status_code_ = url_response.GetStatusCode(); | 249 status_code_ = url_response_.GetStatusCode(); |
246 switch (url_scheme_) { | 250 switch (url_scheme_) { |
247 case SCHEME_CHROME_EXTENSION: | 251 case SCHEME_CHROME_EXTENSION: |
248 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (chrome-extension " | 252 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (chrome-extension " |
249 "response status_code=%"NACL_PRId32")\n", status_code_)); | 253 "response status_code=%"NACL_PRId32")\n", status_code_)); |
250 status_ok = (status_code_ == kExtensionUrlRequestStatusOk); | 254 status_ok = (status_code_ == kExtensionUrlRequestStatusOk); |
251 break; | 255 break; |
252 case SCHEME_DATA: | 256 case SCHEME_DATA: |
253 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (data URI " | 257 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (data URI " |
254 "response status_code=%"NACL_PRId32")\n", status_code_)); | 258 "response status_code=%"NACL_PRId32")\n", status_code_)); |
255 status_ok = (status_code_ == kDataUriRequestStatusOk); | 259 status_ok = (status_code_ == kDataUriRequestStatusOk); |
256 break; | 260 break; |
257 case SCHEME_OTHER: | 261 case SCHEME_OTHER: |
258 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (HTTP response " | 262 PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (HTTP response " |
259 "status_code=%"NACL_PRId32")\n", status_code_)); | 263 "status_code=%"NACL_PRId32")\n", status_code_)); |
260 status_ok = (status_code_ == NACL_HTTP_STATUS_OK); | 264 status_ok = (status_code_ == NACL_HTTP_STATUS_OK); |
261 break; | 265 break; |
262 } | 266 } |
263 | 267 |
264 if (!status_ok) { | 268 if (!status_ok) { |
265 file_open_notify_callback_.Run(PP_ERROR_FAILED); | 269 file_open_notify_callback_.RunAndClear(PP_ERROR_FAILED); |
266 return false; | 270 return false; |
267 } | 271 } |
268 | 272 |
269 return true; | 273 return true; |
270 } | 274 } |
271 | 275 |
272 void FileDownloader::URLLoadStartNotify(int32_t pp_error) { | 276 void FileDownloader::URLLoadStartNotify(int32_t pp_error) { |
273 PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (pp_error=%" | 277 PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (pp_error=%" |
274 NACL_PRId32")\n", pp_error)); | 278 NACL_PRId32")\n", pp_error)); |
275 | 279 |
276 if (!InitialResponseIsValid(pp_error)) | 280 if (!InitialResponseIsValid(pp_error)) { |
| 281 // InitialResponseIsValid() calls file_open_notify_callback_ on errors. |
277 return; | 282 return; |
| 283 } |
| 284 |
| 285 if (open_and_stream_) |
| 286 return FinishStreaming(file_open_notify_callback_); |
| 287 |
| 288 file_open_notify_callback_.RunAndClear(pp_error); |
| 289 } |
| 290 |
| 291 void FileDownloader::URLBufferStartNotify(int32_t pp_error) { |
| 292 PLUGIN_PRINTF(("FileDownloader::URLBufferStartNotify (pp_error=%" |
| 293 NACL_PRId32")\n", pp_error)); |
| 294 |
| 295 if (!InitialResponseIsValid(pp_error)) { |
| 296 // InitialResponseIsValid() calls file_open_notify_callback_ on errors. |
| 297 return; |
| 298 } |
| 299 |
| 300 if (open_and_stream_) |
| 301 return FinishStreaming(file_open_notify_callback_); |
| 302 |
| 303 file_open_notify_callback_.RunAndClear(pp_error); |
| 304 } |
| 305 |
| 306 void FileDownloader::FinishStreaming( |
| 307 const pp::CompletionCallback& callback) { |
| 308 stream_finish_callback_ = callback; |
| 309 |
278 // Finish streaming the body providing an optional callback. | 310 // Finish streaming the body providing an optional callback. |
279 pp::CompletionCallback onload_callback = | 311 if (streaming_to_file()) { |
280 callback_factory_.NewOptionalCallback( | 312 pp::CompletionCallback onload_callback = |
281 &FileDownloader::URLLoadFinishNotify); | 313 callback_factory_.NewOptionalCallback( |
282 pp_error = url_loader_.FinishStreamingToFile(onload_callback); | 314 &FileDownloader::URLLoadFinishNotify); |
283 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); | 315 int32_t pp_error = url_loader_.FinishStreamingToFile(onload_callback); |
284 PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (async_notify_ok=%d)\n", | 316 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); |
285 async_notify_ok)); | 317 PLUGIN_PRINTF(("FileDownloader::FinishStreaming (async_notify_ok=%d)\n", |
286 if (!async_notify_ok) { | 318 async_notify_ok)); |
287 // Call manually to free allocated memory and report errors. This calls | 319 if (!async_notify_ok) { |
288 // |file_open_notify_callback_| with |pp_error| as the parameter. | 320 // Call manually to free allocated memory and report errors. This calls |
289 onload_callback.Run(pp_error); | 321 // |stream_finish_callback_| with |pp_error| as the parameter. |
| 322 onload_callback.RunAndClear(pp_error); |
| 323 } |
| 324 } else { |
| 325 pp::CompletionCallback onread_callback = |
| 326 callback_factory_.NewOptionalCallback( |
| 327 &FileDownloader::URLReadBodyNotify); |
| 328 int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); |
| 329 int32_t pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], |
| 330 temp_size, |
| 331 onread_callback); |
| 332 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); |
| 333 PLUGIN_PRINTF(( |
| 334 "FileDownloader::FinishStreaming (async_notify_ok=%d)\n", |
| 335 async_notify_ok)); |
| 336 if (!async_notify_ok) { |
| 337 onread_callback.RunAndClear(pp_error); |
| 338 } |
290 } | 339 } |
291 } | 340 } |
292 | 341 |
293 void FileDownloader::URLLoadFinishNotify(int32_t pp_error) { | 342 void FileDownloader::URLLoadFinishNotify(int32_t pp_error) { |
294 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (pp_error=%" | 343 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (pp_error=%" |
295 NACL_PRId32")\n", pp_error)); | 344 NACL_PRId32")\n", pp_error)); |
296 if (pp_error != PP_OK) { // Streaming failed. | 345 if (pp_error != PP_OK) { // Streaming failed. |
297 file_open_notify_callback_.Run(pp_error); | 346 stream_finish_callback_.RunAndClear(pp_error); |
298 return; | 347 return; |
299 } | 348 } |
300 | 349 |
301 pp::URLResponseInfo url_response(url_loader_.GetResponseInfo()); | 350 // Validate response again on load (though it should be the same |
302 // Validated on load. | 351 // as it was during InitialResponseIsValid?). |
303 CHECK(url_response.GetStatusCode() == NACL_HTTP_STATUS_OK || | 352 url_response_ = url_loader_.GetResponseInfo(); |
304 url_response.GetStatusCode() == kExtensionUrlRequestStatusOk); | 353 CHECK(url_response_.GetStatusCode() == NACL_HTTP_STATUS_OK || |
| 354 url_response_.GetStatusCode() == kExtensionUrlRequestStatusOk); |
305 | 355 |
306 // Record the full url from the response. | 356 // Record the full url from the response. |
307 pp::Var full_url = url_response.GetURL(); | 357 pp::Var full_url = url_response_.GetURL(); |
308 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (full_url=%s)\n", | 358 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (full_url=%s)\n", |
309 full_url.DebugString().c_str())); | 359 full_url.DebugString().c_str())); |
310 if (!full_url.is_string()) { | 360 if (!full_url.is_string()) { |
311 file_open_notify_callback_.Run(PP_ERROR_FAILED); | 361 stream_finish_callback_.RunAndClear(PP_ERROR_FAILED); |
312 return; | 362 return; |
313 } | 363 } |
314 url_ = full_url.AsString(); | 364 url_ = full_url.AsString(); |
315 | 365 |
316 // The file is now fully downloaded. | 366 // The file is now fully downloaded. |
317 pp::FileRef file(url_response.GetBodyAsFileRef()); | 367 pp::FileRef file(url_response_.GetBodyAsFileRef()); |
318 if (file.is_null()) { | 368 if (file.is_null()) { |
319 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (file=NULL)\n")); | 369 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (file=NULL)\n")); |
320 file_open_notify_callback_.Run(PP_ERROR_FAILED); | 370 stream_finish_callback_.RunAndClear(PP_ERROR_FAILED); |
321 return; | 371 return; |
322 } | 372 } |
323 | 373 |
324 // Open the file providing an optional callback. | 374 // Open the file providing an optional callback. |
325 pp::CompletionCallback onopen_callback = | 375 pp::CompletionCallback onopen_callback = |
326 callback_factory_.NewOptionalCallback(&FileDownloader::FileOpenNotify); | 376 callback_factory_.NewOptionalCallback( |
| 377 &FileDownloader::StreamFinishNotify); |
327 pp_error = file_reader_.Open(file, PP_FILEOPENFLAG_READ, onopen_callback); | 378 pp_error = file_reader_.Open(file, PP_FILEOPENFLAG_READ, onopen_callback); |
328 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); | 379 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); |
329 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (async_notify_ok=%d)\n", | 380 PLUGIN_PRINTF(("FileDownloader::URLLoadFinishNotify (async_notify_ok=%d)\n", |
330 async_notify_ok)); | 381 async_notify_ok)); |
331 if (!async_notify_ok) { | 382 if (!async_notify_ok) { |
332 // Call manually to free allocated memory and report errors. This calls | 383 // Call manually to free allocated memory and report errors. This calls |
333 // |file_open_notify_callback_| with |pp_error| as the parameter. | 384 // |stream_finish_callback_| with |pp_error| as the parameter. |
334 onopen_callback.Run(pp_error); | 385 onopen_callback.RunAndClear(pp_error); |
335 } | 386 } |
336 } | 387 } |
337 | 388 |
338 void FileDownloader::URLBufferStartNotify(int32_t pp_error) { | |
339 PLUGIN_PRINTF(("FileDownloader::URLBufferStartNotify (pp_error=%" | |
340 NACL_PRId32")\n", pp_error)); | |
341 | |
342 if (!InitialResponseIsValid(pp_error)) | |
343 return; | |
344 // Finish streaming the body asynchronously providing a callback. | |
345 pp::CompletionCallback onread_callback = | |
346 callback_factory_.NewOptionalCallback(&FileDownloader::URLReadBodyNotify); | |
347 | |
348 int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); | |
349 pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], | |
350 temp_size, | |
351 onread_callback); | |
352 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); | |
353 PLUGIN_PRINTF(("FileDownloader::URLBufferStartNotify (async_notify_ok=%d)\n", | |
354 async_notify_ok)); | |
355 if (!async_notify_ok) { | |
356 onread_callback.Run(pp_error); | |
357 } | |
358 } | |
359 | |
360 void FileDownloader::URLReadBodyNotify(int32_t pp_error) { | 389 void FileDownloader::URLReadBodyNotify(int32_t pp_error) { |
361 PLUGIN_PRINTF(("FileDownloader::URLReadBodyNotify (pp_error=%" | 390 PLUGIN_PRINTF(("FileDownloader::URLReadBodyNotify (pp_error=%" |
362 NACL_PRId32")\n", pp_error)); | 391 NACL_PRId32")\n", pp_error)); |
363 if (pp_error < PP_OK) { | 392 if (pp_error < PP_OK) { |
364 file_open_notify_callback_.Run(pp_error); | 393 stream_finish_callback_.RunAndClear(pp_error); |
365 } else if (pp_error == PP_OK) { | 394 } else if (pp_error == PP_OK) { |
366 if (streaming_to_user()) { | 395 if (streaming_to_user()) { |
367 data_stream_callback_source_->GetCallback().Run(PP_OK); | 396 data_stream_callback_source_->GetCallback().RunAndClear(PP_OK); |
368 } | 397 } |
369 FileOpenNotify(PP_OK); | 398 StreamFinishNotify(PP_OK); |
370 } else { | 399 } else { |
371 if (streaming_to_buffer()) { | 400 if (streaming_to_buffer()) { |
372 buffer_.insert(buffer_.end(), &temp_buffer_[0], &temp_buffer_[pp_error]); | 401 buffer_.insert(buffer_.end(), &temp_buffer_[0], &temp_buffer_[pp_error]); |
373 } else if (streaming_to_user()) { | 402 } else if (streaming_to_user()) { |
374 PLUGIN_PRINTF(("Running data_stream_callback, temp_buffer_=%p\n", | 403 PLUGIN_PRINTF(("Running data_stream_callback, temp_buffer_=%p\n", |
375 &temp_buffer_[0])); | 404 &temp_buffer_[0])); |
376 StreamCallback cb = data_stream_callback_source_->GetCallback(); | 405 StreamCallback cb = data_stream_callback_source_->GetCallback(); |
377 *(cb.output()) = &temp_buffer_; | 406 *(cb.output()) = &temp_buffer_; |
378 cb.Run(pp_error); | 407 cb.RunAndClear(pp_error); |
379 } | 408 } |
380 pp::CompletionCallback onread_callback = | 409 pp::CompletionCallback onread_callback = |
381 callback_factory_.NewOptionalCallback( | 410 callback_factory_.NewOptionalCallback( |
382 &FileDownloader::URLReadBodyNotify); | 411 &FileDownloader::URLReadBodyNotify); |
383 int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); | 412 int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); |
384 pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], | 413 pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], |
385 temp_size, | 414 temp_size, |
386 onread_callback); | 415 onread_callback); |
387 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); | 416 bool async_notify_ok = (pp_error == PP_OK_COMPLETIONPENDING); |
388 if (!async_notify_ok) { | 417 if (!async_notify_ok) { |
389 onread_callback.Run(pp_error); | 418 onread_callback.RunAndClear(pp_error); |
390 } | 419 } |
391 } | 420 } |
392 } | 421 } |
393 | 422 |
394 bool FileDownloader::GetDownloadProgress( | 423 bool FileDownloader::GetDownloadProgress( |
395 int64_t* bytes_received, | 424 int64_t* bytes_received, |
396 int64_t* total_bytes_to_be_received) const { | 425 int64_t* total_bytes_to_be_received) const { |
397 return url_loader_.GetDownloadProgress(bytes_received, | 426 return url_loader_.GetDownloadProgress(bytes_received, |
398 total_bytes_to_be_received); | 427 total_bytes_to_be_received); |
399 } | 428 } |
400 | 429 |
401 void FileDownloader::FileOpenNotify(int32_t pp_error) { | 430 nacl::string FileDownloader::GetResponseHeaders() const { |
402 PLUGIN_PRINTF(("FileDownloader::FileOpenNotify (pp_error=%"NACL_PRId32")\n", | 431 pp::Var headers = url_response_.GetHeaders(); |
403 pp_error)); | 432 if (!headers.is_string()) { |
404 file_open_notify_callback_.Run(pp_error); | 433 PLUGIN_PRINTF(( |
| 434 "FileDownloader::GetResponseHeaders (headers are not a string)\n")); |
| 435 return nacl::string(); |
| 436 } |
| 437 return headers.AsString(); |
| 438 } |
| 439 |
| 440 void FileDownloader::StreamFinishNotify(int32_t pp_error) { |
| 441 PLUGIN_PRINTF(( |
| 442 "FileDownloader::StreamFinishNotify (pp_error=%"NACL_PRId32")\n", |
| 443 pp_error)); |
| 444 stream_finish_callback_.RunAndClear(pp_error); |
405 } | 445 } |
406 | 446 |
407 bool FileDownloader::streaming_to_file() const { | 447 bool FileDownloader::streaming_to_file() const { |
408 return mode_ == DOWNLOAD_TO_FILE; | 448 return mode_ == DOWNLOAD_TO_FILE; |
409 } | 449 } |
410 | 450 |
411 bool FileDownloader::streaming_to_buffer() const { | 451 bool FileDownloader::streaming_to_buffer() const { |
412 return mode_ == DOWNLOAD_TO_BUFFER; | 452 return mode_ == DOWNLOAD_TO_BUFFER; |
413 } | 453 } |
414 | 454 |
415 bool FileDownloader::streaming_to_user() const { | 455 bool FileDownloader::streaming_to_user() const { |
416 return mode_ == DOWNLOAD_STREAM; | 456 return mode_ == DOWNLOAD_STREAM; |
417 } | 457 } |
418 | 458 |
419 bool FileDownloader::not_streaming() const { | 459 bool FileDownloader::not_streaming() const { |
420 return mode_ == DOWNLOAD_NONE; | 460 return mode_ == DOWNLOAD_NONE; |
421 } | 461 } |
422 | 462 |
423 } // namespace plugin | 463 } // namespace plugin |
OLD | NEW |