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 "chrome/browser/extensions/api/downloads/downloads_api.h" | 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cctype> | 8 #include <cctype> |
9 #include <iterator> | 9 #include <iterator> |
10 #include <set> | 10 #include <set> |
11 #include <string> | 11 #include <string> |
12 | 12 |
13 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
14 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
16 #include "base/callback.h" | 16 #include "base/callback.h" |
| 17 #include "base/file_path.h" |
17 #include "base/json/json_writer.h" | 18 #include "base/json/json_writer.h" |
18 #include "base/lazy_instance.h" | 19 #include "base/lazy_instance.h" |
19 #include "base/logging.h" | 20 #include "base/logging.h" |
20 #include "base/metrics/histogram.h" | 21 #include "base/metrics/histogram.h" |
21 #include "base/stl_util.h" | 22 #include "base/stl_util.h" |
22 #include "base/string16.h" | 23 #include "base/string16.h" |
23 #include "base/string_split.h" | 24 #include "base/string_split.h" |
24 #include "base/string_util.h" | 25 #include "base/string_util.h" |
25 #include "base/stringprintf.h" | 26 #include "base/stringprintf.h" |
26 #include "base/values.h" | 27 #include "base/values.h" |
27 #include "chrome/browser/browser_process.h" | 28 #include "chrome/browser/browser_process.h" |
28 #include "chrome/browser/download/download_danger_prompt.h" | 29 #include "chrome/browser/download/download_danger_prompt.h" |
29 #include "chrome/browser/download/download_file_icon_extractor.h" | 30 #include "chrome/browser/download/download_file_icon_extractor.h" |
30 #include "chrome/browser/download/download_query.h" | 31 #include "chrome/browser/download/download_query.h" |
31 #include "chrome/browser/download/download_service.h" | 32 #include "chrome/browser/download/download_service.h" |
32 #include "chrome/browser/download/download_service_factory.h" | 33 #include "chrome/browser/download/download_service_factory.h" |
33 #include "chrome/browser/download/download_util.h" | 34 #include "chrome/browser/download/download_util.h" |
34 #include "chrome/browser/extensions/event_names.h" | 35 #include "chrome/browser/extensions/event_names.h" |
35 #include "chrome/browser/extensions/event_router.h" | 36 #include "chrome/browser/extensions/event_router.h" |
36 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 37 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
| 38 #include "chrome/browser/extensions/extension_info_map.h" |
37 #include "chrome/browser/extensions/extension_system.h" | 39 #include "chrome/browser/extensions/extension_system.h" |
38 #include "chrome/browser/icon_loader.h" | 40 #include "chrome/browser/icon_loader.h" |
39 #include "chrome/browser/icon_manager.h" | 41 #include "chrome/browser/icon_manager.h" |
40 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 42 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
41 #include "chrome/browser/ui/browser.h" | 43 #include "chrome/browser/ui/browser.h" |
42 #include "chrome/common/cancelable_task_tracker.h" | 44 #include "chrome/common/cancelable_task_tracker.h" |
43 #include "chrome/common/chrome_notification_types.h" | 45 #include "chrome/common/chrome_notification_types.h" |
44 #include "chrome/common/extensions/api/downloads.h" | 46 #include "chrome/common/extensions/api/downloads.h" |
45 #include "content/public/browser/download_interrupt_reasons.h" | 47 #include "content/public/browser/download_interrupt_reasons.h" |
46 #include "content/public/browser/download_item.h" | 48 #include "content/public/browser/download_item.h" |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 } | 177 } |
176 | 178 |
177 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { | 179 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { |
178 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { | 180 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { |
179 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) | 181 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) |
180 return static_cast<DownloadItem::DownloadState>(i); | 182 return static_cast<DownloadItem::DownloadState>(i); |
181 } | 183 } |
182 return DownloadItem::MAX_DOWNLOAD_STATE; | 184 return DownloadItem::MAX_DOWNLOAD_STATE; |
183 } | 185 } |
184 | 186 |
185 bool ValidateFilename(const string16& filename) { | 187 bool ValidateFilename(const FilePath& filename) { |
186 // TODO(benjhayden): More robust validation of filename. | 188 return !filename.empty() && |
187 if ((filename.find('/') != string16::npos) || | 189 (filename.BaseName().value() != FilePath::kCurrentDirectory) && |
188 (filename.find('\\') != string16::npos)) | 190 !filename.ReferencesParent() && |
189 return false; | 191 !filename.IsAbsolute(); |
190 if (filename.size() >= 2u && filename[0] == L'.' && filename[1] == L'.') | |
191 return false; | |
192 return true; | |
193 } | 192 } |
194 | 193 |
195 std::string TimeToISO8601(const base::Time& t) { | 194 std::string TimeToISO8601(const base::Time& t) { |
196 base::Time::Exploded exploded; | 195 base::Time::Exploded exploded; |
197 t.UTCExplode(&exploded); | 196 t.UTCExplode(&exploded); |
198 return base::StringPrintf( | 197 return base::StringPrintf( |
199 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month, | 198 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month, |
200 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second, | 199 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second, |
201 exploded.millisecond); | 200 exploded.millisecond); |
202 } | 201 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 }; | 253 }; |
255 | 254 |
256 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( | 255 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( |
257 const FilePath& path, | 256 const FilePath& path, |
258 IconLoader::IconSize icon_size, | 257 IconLoader::IconSize icon_size, |
259 IconURLCallback callback) { | 258 IconURLCallback callback) { |
260 callback_ = callback; | 259 callback_ = callback; |
261 IconManager* im = g_browser_process->icon_manager(); | 260 IconManager* im = g_browser_process->icon_manager(); |
262 // The contents of the file at |path| may have changed since a previous | 261 // The contents of the file at |path| may have changed since a previous |
263 // request, in which case the associated icon may also have changed. | 262 // request, in which case the associated icon may also have changed. |
264 // Therefore, for the moment we always call LoadIcon instead of attempting | 263 // Therefore, always call LoadIcon instead of attempting a LookupIcon. |
265 // a LookupIcon. | |
266 im->LoadIcon(path, | 264 im->LoadIcon(path, |
267 icon_size, | 265 icon_size, |
268 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, | 266 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, |
269 base::Unretained(this)), | 267 base::Unretained(this)), |
270 &cancelable_task_tracker_); | 268 &cancelable_task_tracker_); |
271 return true; | 269 return true; |
272 } | 270 } |
273 | 271 |
274 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { | 272 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { |
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 // TODO(benjhayden): Consider switching from LazyInstance to explicit string | 399 // TODO(benjhayden): Consider switching from LazyInstance to explicit string |
402 // comparisons. | 400 // comparisons. |
403 static base::LazyInstance<SortTypeMap> sorter_types = | 401 static base::LazyInstance<SortTypeMap> sorter_types = |
404 LAZY_INSTANCE_INITIALIZER; | 402 LAZY_INSTANCE_INITIALIZER; |
405 if (sorter_types.Get().size() == 0) | 403 if (sorter_types.Get().size() == 0) |
406 InitSortTypeMap(sorter_types.Get()); | 404 InitSortTypeMap(sorter_types.Get()); |
407 | 405 |
408 std::vector<std::string> order_by_strs; | 406 std::vector<std::string> order_by_strs; |
409 base::SplitString(order_by_str, ' ', &order_by_strs); | 407 base::SplitString(order_by_str, ' ', &order_by_strs); |
410 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); | 408 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); |
411 iter != order_by_strs.end(); ++iter) { | 409 iter != order_by_strs.end(); ++iter) { |
412 std::string term_str = *iter; | 410 std::string term_str = *iter; |
413 if (term_str.empty()) | 411 if (term_str.empty()) |
414 continue; | 412 continue; |
415 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; | 413 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; |
416 if (term_str[0] == '-') { | 414 if (term_str[0] == '-') { |
417 direction = DownloadQuery::DESCENDING; | 415 direction = DownloadQuery::DESCENDING; |
418 term_str = term_str.substr(1); | 416 term_str = term_str.substr(1); |
419 } | 417 } |
420 SortTypeMap::const_iterator sorter_type = | 418 SortTypeMap::const_iterator sorter_type = |
421 sorter_types.Get().find(term_str); | 419 sorter_types.Get().find(term_str); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); | 534 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); |
537 return (data == NULL) ? NULL : | 535 return (data == NULL) ? NULL : |
538 static_cast<ExtensionDownloadsEventRouterData*>(data); | 536 static_cast<ExtensionDownloadsEventRouterData*>(data); |
539 } | 537 } |
540 | 538 |
541 explicit ExtensionDownloadsEventRouterData( | 539 explicit ExtensionDownloadsEventRouterData( |
542 DownloadItem* download_item, | 540 DownloadItem* download_item, |
543 scoped_ptr<base::DictionaryValue> json_item) | 541 scoped_ptr<base::DictionaryValue> json_item) |
544 : updated_(0), | 542 : updated_(0), |
545 changed_fired_(0), | 543 changed_fired_(0), |
546 json_(json_item.Pass()) { | 544 json_(json_item.Pass()), |
| 545 determined_overwrite_(false) { |
547 download_item->SetUserData(kKey, this); | 546 download_item->SetUserData(kKey, this); |
548 } | 547 } |
549 | 548 |
550 virtual ~ExtensionDownloadsEventRouterData() { | 549 virtual ~ExtensionDownloadsEventRouterData() { |
551 if (updated_ > 0) { | 550 if (updated_ > 0) { |
552 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", | 551 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", |
553 (changed_fired_ * 100 / updated_)); | 552 (changed_fired_ * 100 / updated_)); |
554 } | 553 } |
555 } | 554 } |
556 | 555 |
557 const base::DictionaryValue& json() const { return *json_.get(); } | 556 const base::DictionaryValue& json() const { return *json_.get(); } |
558 void set_json(scoped_ptr<base::DictionaryValue> json_item) { | 557 void set_json(scoped_ptr<base::DictionaryValue> json_item) { |
559 json_ = json_item.Pass(); | 558 json_ = json_item.Pass(); |
560 } | 559 } |
561 | 560 |
562 void OnItemUpdated() { ++updated_; } | 561 void OnItemUpdated() { ++updated_; } |
563 void OnChangedFired() { ++changed_fired_; } | 562 void OnChangedFired() { ++changed_fired_; } |
564 | 563 |
| 564 void set_filename_change_callbacks( |
| 565 const base::Closure& no_change, |
| 566 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { |
| 567 filename_no_change_ = no_change; |
| 568 filename_change_ = change; |
| 569 } |
| 570 |
| 571 void ClearPendingDeterminers() { |
| 572 determiners_.clear(); |
| 573 determined_filename_.clear(); |
| 574 determined_overwrite_ = false; |
| 575 determiner_ = DeterminerInfo(); |
| 576 filename_no_change_ = base::Closure(); |
| 577 filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback(); |
| 578 } |
| 579 |
| 580 void ExtensionUnloaded(const std::string& extension_id) { |
| 581 // Remove this extension from |determiners_|. |
| 582 for (DeterminerInfoVector::iterator iter = determiners_.begin(); |
| 583 iter != determiners_.end();) { |
| 584 if (iter->extension_id == extension_id) { |
| 585 iter = determiners_.erase(iter); |
| 586 } else { |
| 587 ++iter; |
| 588 } |
| 589 } |
| 590 // If we just removed the last unreported determiner, then we need to call a |
| 591 // callback. |
| 592 CheckAllDeterminersCalled(); |
| 593 } |
| 594 |
| 595 void AddPendingDeterminer(const std::string& extension_id, |
| 596 const std::string& sub_event_id, |
| 597 const base::Time& installed) { |
| 598 determiners_.push_back(DeterminerInfo( |
| 599 extension_id, sub_event_id, installed)); |
| 600 } |
| 601 |
| 602 bool DeterminerCallback( |
| 603 const std::string& extension_id, |
| 604 const std::string& sub_event_id, |
| 605 const FilePath& filename, |
| 606 bool overwrite) { |
| 607 bool filename_valid = ValidateFilename(filename); |
| 608 bool found_info = false; |
| 609 for (int index = 0; index < static_cast<int>(determiners_.size()); |
| 610 ++index) { |
| 611 if ((determiners_[index].extension_id == extension_id) && |
| 612 (determiners_[index].sub_event_id == sub_event_id)) { |
| 613 found_info = true; |
| 614 DCHECK(!determiners_[index].reported); |
| 615 determiners_[index].reported = true; |
| 616 if (!determiner_.extension_id.empty() && |
| 617 (determiners_[index].extension_id == determiner_.extension_id)) { |
| 618 DCHECK_NE(determiners_[index].sub_event_id, determiner_.sub_event_id); |
| 619 } |
| 620 // Do not use filename if another determiner has already overridden the |
| 621 // filename and they take precedence. Extensions that were installed |
| 622 // later take precedence over previous extensions, and listeners that |
| 623 // were added later take precedence over previous listeners. |
| 624 if (filename_valid && |
| 625 (determiner_.extension_id.empty() || |
| 626 ((determiners_[index].extension_id == determiner_.extension_id) ? |
| 627 (determiners_[index].sub_event_id > determiner_.sub_event_id) : |
| 628 (determiners_[index].install_time > determiner_.install_time)))) { |
| 629 determined_filename_ = filename; |
| 630 determined_overwrite_ = overwrite; |
| 631 determiner_ = determiners_[index]; |
| 632 } |
| 633 } |
| 634 } |
| 635 if (!found_info) |
| 636 return false; |
| 637 CheckAllDeterminersCalled(); |
| 638 return filename.empty() || filename_valid; |
| 639 } |
| 640 |
565 private: | 641 private: |
| 642 struct DeterminerInfo { |
| 643 DeterminerInfo(); |
| 644 DeterminerInfo(const std::string& e_id, |
| 645 const std::string& sub_id, |
| 646 const base::Time& installed); |
| 647 ~DeterminerInfo(); |
| 648 |
| 649 std::string extension_id; |
| 650 std::string sub_event_id; |
| 651 base::Time install_time; |
| 652 bool reported; |
| 653 }; |
| 654 typedef std::vector<DeterminerInfo> DeterminerInfoVector; |
| 655 |
566 static const char kKey[]; | 656 static const char kKey[]; |
567 | 657 |
| 658 // This is safe to call even while not waiting for determiners to call back; |
| 659 // in that case, the callbacks will be null so they won't be Run. |
| 660 void CheckAllDeterminersCalled() { |
| 661 for (DeterminerInfoVector::iterator iter = determiners_.begin(); |
| 662 iter != determiners_.end(); ++iter) { |
| 663 if (!iter->reported) |
| 664 return; |
| 665 } |
| 666 if (determined_filename_.empty()) { |
| 667 if (!filename_no_change_.is_null()) |
| 668 filename_no_change_.Run(); |
| 669 } else { |
| 670 if (!filename_change_.is_null()) |
| 671 filename_change_.Run(determined_filename_, determined_overwrite_); |
| 672 } |
| 673 ClearPendingDeterminers(); |
| 674 } |
| 675 |
568 int updated_; | 676 int updated_; |
569 int changed_fired_; | 677 int changed_fired_; |
570 scoped_ptr<base::DictionaryValue> json_; | 678 scoped_ptr<base::DictionaryValue> json_; |
571 | 679 |
| 680 base::Closure filename_no_change_; |
| 681 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_; |
| 682 |
| 683 DeterminerInfoVector determiners_; |
| 684 |
| 685 FilePath determined_filename_; |
| 686 bool determined_overwrite_; |
| 687 DeterminerInfo determiner_; |
| 688 |
572 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); | 689 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); |
573 }; | 690 }; |
574 | 691 |
| 692 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo( |
| 693 const std::string& e_id, |
| 694 const std::string& sub_id, |
| 695 const base::Time& installed) |
| 696 : extension_id(e_id), |
| 697 sub_event_id(sub_id), |
| 698 install_time(installed), |
| 699 reported(false) { |
| 700 } |
| 701 |
| 702 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo() |
| 703 : reported(false) { |
| 704 } |
| 705 |
| 706 ExtensionDownloadsEventRouterData::DeterminerInfo::~DeterminerInfo() {} |
| 707 |
575 const char ExtensionDownloadsEventRouterData::kKey[] = | 708 const char ExtensionDownloadsEventRouterData::kKey[] = |
576 "DownloadItem ExtensionDownloadsEventRouterData"; | 709 "DownloadItem ExtensionDownloadsEventRouterData"; |
577 | 710 |
578 class ManagerDestructionObserver : public DownloadManager::Observer { | 711 class ManagerDestructionObserver : public DownloadManager::Observer { |
579 public: | 712 public: |
580 static void CheckForHistoryFilesRemoval(DownloadManager* manager) { | 713 static void CheckForHistoryFilesRemoval(DownloadManager* manager) { |
581 if (!manager) | 714 if (!manager) |
582 return; | 715 return; |
583 if (!manager_file_existence_last_checked_) | 716 if (!manager_file_existence_last_checked_) |
584 manager_file_existence_last_checked_ = | 717 manager_file_existence_last_checked_ = |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 | 760 |
628 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver); | 761 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver); |
629 }; | 762 }; |
630 | 763 |
631 std::map<DownloadManager*, ManagerDestructionObserver*>* | 764 std::map<DownloadManager*, ManagerDestructionObserver*>* |
632 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL; | 765 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL; |
633 | 766 |
634 } // namespace | 767 } // namespace |
635 | 768 |
636 DownloadsDownloadFunction::DownloadsDownloadFunction() {} | 769 DownloadsDownloadFunction::DownloadsDownloadFunction() {} |
| 770 |
637 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} | 771 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} |
638 | 772 |
639 bool DownloadsDownloadFunction::RunImpl() { | 773 bool DownloadsDownloadFunction::RunImpl() { |
640 scoped_ptr<extensions::api::downloads::Download::Params> params( | 774 scoped_ptr<extensions::api::downloads::Download::Params> params( |
641 extensions::api::downloads::Download::Params::Create(*args_)); | 775 extensions::api::downloads::Download::Params::Create(*args_)); |
642 EXTENSION_FUNCTION_VALIDATE(params.get()); | 776 EXTENSION_FUNCTION_VALIDATE(params.get()); |
643 const extensions::api::downloads::DownloadOptions& options = params->options; | 777 const extensions::api::downloads::DownloadOptions& options = params->options; |
644 GURL download_url(options.url); | 778 GURL download_url(options.url); |
645 if (!download_url.is_valid() || | 779 if (!download_url.is_valid() || |
646 (!download_url.SchemeIs("data") && | 780 (!download_url.SchemeIs("data") && |
(...skipping 16 matching lines...) Expand all Loading... |
663 | 797 |
664 if (options.filename.get()) { | 798 if (options.filename.get()) { |
665 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of | 799 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of |
666 // std::strings. Can't get filename16 from options.ToValue() because that | 800 // std::strings. Can't get filename16 from options.ToValue() because that |
667 // converts it from std::string. | 801 // converts it from std::string. |
668 base::DictionaryValue* options_value = NULL; | 802 base::DictionaryValue* options_value = NULL; |
669 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); | 803 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); |
670 string16 filename16; | 804 string16 filename16; |
671 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( | 805 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( |
672 kFilenameKey, &filename16)); | 806 kFilenameKey, &filename16)); |
673 if (!ValidateFilename(filename16)) { | 807 #if defined(OS_WIN) |
| 808 FilePath file_path(filename16); |
| 809 #elif defined(OS_POSIX) |
| 810 FilePath file_path(*options.filename.get()); |
| 811 #endif |
| 812 if (!ValidateFilename(file_path) || |
| 813 (file_path.DirName().value() != FilePath::kCurrentDirectory)) { |
674 error_ = download_extension_errors::kGenericError; | 814 error_ = download_extension_errors::kGenericError; |
675 return false; | 815 return false; |
676 } | 816 } |
677 // TODO(benjhayden) Ensure that this filename is interpreted as a path | 817 // TODO(benjhayden) Ensure that this filename is interpreted as a path |
678 // relative to the default downloads directory without allowing '..'. | 818 // relative to the default downloads directory without allowing '..'. |
679 download_params->set_suggested_name(filename16); | 819 download_params->set_suggested_name(filename16); |
680 } | 820 } |
681 | 821 |
682 if (options.save_as.get()) | 822 if (options.save_as.get()) |
683 download_params->set_prompt(*options.save_as.get()); | 823 download_params->set_prompt(*options.save_as.get()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 DCHECK_EQ(net::OK, error); | 863 DCHECK_EQ(net::OK, error); |
724 SetResult(base::Value::CreateIntegerValue(item->GetId())); | 864 SetResult(base::Value::CreateIntegerValue(item->GetId())); |
725 } else { | 865 } else { |
726 DCHECK_NE(net::OK, error); | 866 DCHECK_NE(net::OK, error); |
727 error_ = net::ErrorToString(error); | 867 error_ = net::ErrorToString(error); |
728 } | 868 } |
729 SendResponse(error_.empty()); | 869 SendResponse(error_.empty()); |
730 } | 870 } |
731 | 871 |
732 DownloadsSearchFunction::DownloadsSearchFunction() {} | 872 DownloadsSearchFunction::DownloadsSearchFunction() {} |
| 873 |
733 DownloadsSearchFunction::~DownloadsSearchFunction() {} | 874 DownloadsSearchFunction::~DownloadsSearchFunction() {} |
734 | 875 |
735 bool DownloadsSearchFunction::RunImpl() { | 876 bool DownloadsSearchFunction::RunImpl() { |
736 scoped_ptr<extensions::api::downloads::Search::Params> params( | 877 scoped_ptr<extensions::api::downloads::Search::Params> params( |
737 extensions::api::downloads::Search::Params::Create(*args_)); | 878 extensions::api::downloads::Search::Params::Create(*args_)); |
738 EXTENSION_FUNCTION_VALIDATE(params.get()); | 879 EXTENSION_FUNCTION_VALIDATE(params.get()); |
739 DownloadManager* manager = NULL; | 880 DownloadManager* manager = NULL; |
740 DownloadManager* incognito_manager = NULL; | 881 DownloadManager* incognito_manager = NULL; |
741 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); | 882 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); |
742 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager); | 883 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager); |
(...skipping 17 matching lines...) Expand all Loading... |
760 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( | 901 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( |
761 *it, off_record)); | 902 *it, off_record)); |
762 json_results->Append(json_item.release()); | 903 json_results->Append(json_item.release()); |
763 } | 904 } |
764 SetResult(json_results); | 905 SetResult(json_results); |
765 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); | 906 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); |
766 return true; | 907 return true; |
767 } | 908 } |
768 | 909 |
769 DownloadsPauseFunction::DownloadsPauseFunction() {} | 910 DownloadsPauseFunction::DownloadsPauseFunction() {} |
| 911 |
770 DownloadsPauseFunction::~DownloadsPauseFunction() {} | 912 DownloadsPauseFunction::~DownloadsPauseFunction() {} |
771 | 913 |
772 bool DownloadsPauseFunction::RunImpl() { | 914 bool DownloadsPauseFunction::RunImpl() { |
773 scoped_ptr<extensions::api::downloads::Pause::Params> params( | 915 scoped_ptr<extensions::api::downloads::Pause::Params> params( |
774 extensions::api::downloads::Pause::Params::Create(*args_)); | 916 extensions::api::downloads::Pause::Params::Create(*args_)); |
775 EXTENSION_FUNCTION_VALIDATE(params.get()); | 917 EXTENSION_FUNCTION_VALIDATE(params.get()); |
776 DownloadItem* download_item = GetDownloadIfInProgress( | 918 DownloadItem* download_item = GetDownloadIfInProgress( |
777 profile(), include_incognito(), params->download_id); | 919 profile(), include_incognito(), params->download_id); |
778 if (download_item == NULL) { | 920 if (download_item == NULL) { |
779 // This could be due to an invalid download ID, or it could be due to the | 921 // This could be due to an invalid download ID, or it could be due to the |
780 // download not being currently active. | 922 // download not being currently active. |
781 error_ = download_extension_errors::kInvalidOperationError; | 923 error_ = download_extension_errors::kInvalidOperationError; |
782 } else { | 924 } else { |
783 // If the item is already paused, this is a no-op and the | 925 // If the item is already paused, this is a no-op and the |
784 // operation will silently succeed. | 926 // operation will silently succeed. |
785 download_item->Pause(); | 927 download_item->Pause(); |
786 } | 928 } |
787 if (error_.empty()) | 929 if (error_.empty()) |
788 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE); | 930 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE); |
789 return error_.empty(); | 931 return error_.empty(); |
790 } | 932 } |
791 | 933 |
792 DownloadsResumeFunction::DownloadsResumeFunction() {} | 934 DownloadsResumeFunction::DownloadsResumeFunction() {} |
| 935 |
793 DownloadsResumeFunction::~DownloadsResumeFunction() {} | 936 DownloadsResumeFunction::~DownloadsResumeFunction() {} |
794 | 937 |
795 bool DownloadsResumeFunction::RunImpl() { | 938 bool DownloadsResumeFunction::RunImpl() { |
796 scoped_ptr<extensions::api::downloads::Resume::Params> params( | 939 scoped_ptr<extensions::api::downloads::Resume::Params> params( |
797 extensions::api::downloads::Resume::Params::Create(*args_)); | 940 extensions::api::downloads::Resume::Params::Create(*args_)); |
798 EXTENSION_FUNCTION_VALIDATE(params.get()); | 941 EXTENSION_FUNCTION_VALIDATE(params.get()); |
799 DownloadItem* download_item = GetDownloadIfInProgress( | 942 DownloadItem* download_item = GetDownloadIfInProgress( |
800 profile(), include_incognito(), params->download_id); | 943 profile(), include_incognito(), params->download_id); |
801 if (download_item == NULL) { | 944 if (download_item == NULL) { |
802 // This could be due to an invalid download ID, or it could be due to the | 945 // This could be due to an invalid download ID, or it could be due to the |
803 // download not being currently active. | 946 // download not being currently active. |
804 error_ = download_extension_errors::kInvalidOperationError; | 947 error_ = download_extension_errors::kInvalidOperationError; |
805 } else { | 948 } else { |
806 // Note that if the item isn't paused, this will be a no-op, and | 949 // Note that if the item isn't paused, this will be a no-op, and |
807 // we will silently treat the extension call as a success. | 950 // the extension call will seem successful. |
808 download_item->Resume(); | 951 download_item->Resume(); |
809 } | 952 } |
810 if (error_.empty()) | 953 if (error_.empty()) |
811 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); | 954 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); |
812 return error_.empty(); | 955 return error_.empty(); |
813 } | 956 } |
814 | 957 |
815 DownloadsCancelFunction::DownloadsCancelFunction() {} | 958 DownloadsCancelFunction::DownloadsCancelFunction() {} |
| 959 |
816 DownloadsCancelFunction::~DownloadsCancelFunction() {} | 960 DownloadsCancelFunction::~DownloadsCancelFunction() {} |
817 | 961 |
818 bool DownloadsCancelFunction::RunImpl() { | 962 bool DownloadsCancelFunction::RunImpl() { |
819 scoped_ptr<extensions::api::downloads::Resume::Params> params( | 963 scoped_ptr<extensions::api::downloads::Resume::Params> params( |
820 extensions::api::downloads::Resume::Params::Create(*args_)); | 964 extensions::api::downloads::Resume::Params::Create(*args_)); |
821 EXTENSION_FUNCTION_VALIDATE(params.get()); | 965 EXTENSION_FUNCTION_VALIDATE(params.get()); |
822 DownloadItem* download_item = GetDownloadIfInProgress( | 966 DownloadItem* download_item = GetDownloadIfInProgress( |
823 profile(), include_incognito(), params->download_id); | 967 profile(), include_incognito(), params->download_id); |
824 if (download_item != NULL) | 968 if (download_item != NULL) |
825 download_item->Cancel(true); | 969 download_item->Cancel(true); |
826 // |download_item| can be NULL if the download ID was invalid or if the | 970 // |download_item| can be NULL if the download ID was invalid or if the |
827 // download is not currently active. Either way, we don't consider it a | 971 // download is not currently active. Either way, it's not a failure. |
828 // failure. | |
829 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); | 972 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); |
830 return true; | 973 return true; |
831 } | 974 } |
832 | 975 |
833 DownloadsEraseFunction::DownloadsEraseFunction() {} | 976 DownloadsEraseFunction::DownloadsEraseFunction() {} |
| 977 |
834 DownloadsEraseFunction::~DownloadsEraseFunction() {} | 978 DownloadsEraseFunction::~DownloadsEraseFunction() {} |
835 | 979 |
836 bool DownloadsEraseFunction::RunImpl() { | 980 bool DownloadsEraseFunction::RunImpl() { |
837 scoped_ptr<extensions::api::downloads::Erase::Params> params( | 981 scoped_ptr<extensions::api::downloads::Erase::Params> params( |
838 extensions::api::downloads::Erase::Params::Create(*args_)); | 982 extensions::api::downloads::Erase::Params::Create(*args_)); |
839 EXTENSION_FUNCTION_VALIDATE(params.get()); | 983 EXTENSION_FUNCTION_VALIDATE(params.get()); |
840 DownloadManager* manager = NULL; | 984 DownloadManager* manager = NULL; |
841 DownloadManager* incognito_manager = NULL; | 985 DownloadManager* incognito_manager = NULL; |
842 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); | 986 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); |
843 DownloadQuery::DownloadVector results; | 987 DownloadQuery::DownloadVector results; |
844 RunDownloadQuery(params->query, | 988 RunDownloadQuery(params->query, |
845 manager, | 989 manager, |
846 incognito_manager, | 990 incognito_manager, |
847 &error_, | 991 &error_, |
848 &results); | 992 &results); |
849 if (!error_.empty()) | 993 if (!error_.empty()) |
850 return false; | 994 return false; |
851 base::ListValue* json_results = new base::ListValue(); | 995 base::ListValue* json_results = new base::ListValue(); |
852 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); | 996 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); |
853 it != results.end(); ++it) { | 997 it != results.end(); ++it) { |
854 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); | 998 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); |
855 (*it)->Remove(); | 999 (*it)->Remove(); |
856 } | 1000 } |
857 SetResult(json_results); | 1001 SetResult(json_results); |
858 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); | 1002 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); |
859 return true; | 1003 return true; |
860 } | 1004 } |
861 | 1005 |
862 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() {} | 1006 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} |
863 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} | |
864 | 1007 |
865 bool DownloadsSetDestinationFunction::RunImpl() { | |
866 scoped_ptr<extensions::api::downloads::SetDestination::Params> params( | |
867 extensions::api::downloads::SetDestination::Params::Create(*args_)); | |
868 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
869 error_ = download_extension_errors::kNotImplementedError; | |
870 if (error_.empty()) | |
871 RecordApiFunctions(DOWNLOADS_FUNCTION_SET_DESTINATION); | |
872 return error_.empty(); | |
873 } | |
874 | |
875 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} | |
876 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} | 1008 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} |
877 | 1009 |
878 bool DownloadsAcceptDangerFunction::RunImpl() { | 1010 bool DownloadsAcceptDangerFunction::RunImpl() { |
879 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( | 1011 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( |
880 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); | 1012 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); |
881 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1013 EXTENSION_FUNCTION_VALIDATE(params.get()); |
882 DownloadItem* download_item = GetDownloadIfInProgress( | 1014 DownloadItem* download_item = GetDownloadIfInProgress( |
883 profile(), include_incognito(), params->download_id); | 1015 profile(), include_incognito(), params->download_id); |
884 content::WebContents* web_contents = | 1016 content::WebContents* web_contents = |
885 dispatcher()->delegate()->GetAssociatedWebContents(); | 1017 dispatcher()->delegate()->GetAssociatedWebContents(); |
(...skipping 23 matching lines...) Expand all Loading... |
909 if (accept) { | 1041 if (accept) { |
910 DownloadItem* download_item = GetDownloadIfInProgress( | 1042 DownloadItem* download_item = GetDownloadIfInProgress( |
911 profile(), include_incognito(), download_id); | 1043 profile(), include_incognito(), download_id); |
912 if (download_item) | 1044 if (download_item) |
913 download_item->DangerousDownloadValidated(); | 1045 download_item->DangerousDownloadValidated(); |
914 } | 1046 } |
915 SendResponse(error_.empty()); | 1047 SendResponse(error_.empty()); |
916 } | 1048 } |
917 | 1049 |
918 DownloadsShowFunction::DownloadsShowFunction() {} | 1050 DownloadsShowFunction::DownloadsShowFunction() {} |
| 1051 |
919 DownloadsShowFunction::~DownloadsShowFunction() {} | 1052 DownloadsShowFunction::~DownloadsShowFunction() {} |
920 | 1053 |
921 bool DownloadsShowFunction::RunImpl() { | 1054 bool DownloadsShowFunction::RunImpl() { |
922 scoped_ptr<extensions::api::downloads::Show::Params> params( | 1055 scoped_ptr<extensions::api::downloads::Show::Params> params( |
923 extensions::api::downloads::Show::Params::Create(*args_)); | 1056 extensions::api::downloads::Show::Params::Create(*args_)); |
924 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1057 EXTENSION_FUNCTION_VALIDATE(params.get()); |
925 DownloadItem* download_item = GetDownload( | 1058 DownloadItem* download_item = GetDownload( |
926 profile(), include_incognito(), params->download_id); | 1059 profile(), include_incognito(), params->download_id); |
927 if (!download_item) { | 1060 if (!download_item) { |
928 error_ = download_extension_errors::kInvalidOperationError; | 1061 error_ = download_extension_errors::kInvalidOperationError; |
929 return false; | 1062 return false; |
930 } | 1063 } |
931 download_item->ShowDownloadInShell(); | 1064 download_item->ShowDownloadInShell(); |
932 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); | 1065 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); |
933 return true; | 1066 return true; |
934 } | 1067 } |
935 | 1068 |
936 DownloadsOpenFunction::DownloadsOpenFunction() {} | 1069 DownloadsOpenFunction::DownloadsOpenFunction() {} |
| 1070 |
937 DownloadsOpenFunction::~DownloadsOpenFunction() {} | 1071 DownloadsOpenFunction::~DownloadsOpenFunction() {} |
938 | 1072 |
939 bool DownloadsOpenFunction::RunImpl() { | 1073 bool DownloadsOpenFunction::RunImpl() { |
940 scoped_ptr<extensions::api::downloads::Open::Params> params( | 1074 scoped_ptr<extensions::api::downloads::Open::Params> params( |
941 extensions::api::downloads::Open::Params::Create(*args_)); | 1075 extensions::api::downloads::Open::Params::Create(*args_)); |
942 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1076 EXTENSION_FUNCTION_VALIDATE(params.get()); |
943 DownloadItem* download_item = GetDownload( | 1077 DownloadItem* download_item = GetDownload( |
944 profile(), include_incognito(), params->download_id); | 1078 profile(), include_incognito(), params->download_id); |
945 if (!download_item || !download_item->IsComplete()) { | 1079 if (!download_item || !download_item->IsComplete()) { |
946 error_ = download_extension_errors::kInvalidOperationError; | 1080 error_ = download_extension_errors::kInvalidOperationError; |
947 return false; | 1081 return false; |
948 } | 1082 } |
949 download_item->OpenDownload(); | 1083 download_item->OpenDownload(); |
950 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); | 1084 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); |
951 return true; | 1085 return true; |
952 } | 1086 } |
953 | 1087 |
954 DownloadsDragFunction::DownloadsDragFunction() {} | 1088 DownloadsDragFunction::DownloadsDragFunction() {} |
| 1089 |
955 DownloadsDragFunction::~DownloadsDragFunction() {} | 1090 DownloadsDragFunction::~DownloadsDragFunction() {} |
956 | 1091 |
957 bool DownloadsDragFunction::RunImpl() { | 1092 bool DownloadsDragFunction::RunImpl() { |
958 scoped_ptr<extensions::api::downloads::Drag::Params> params( | 1093 scoped_ptr<extensions::api::downloads::Drag::Params> params( |
959 extensions::api::downloads::Drag::Params::Create(*args_)); | 1094 extensions::api::downloads::Drag::Params::Create(*args_)); |
960 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1095 EXTENSION_FUNCTION_VALIDATE(params.get()); |
961 DownloadItem* download_item = GetDownload( | 1096 DownloadItem* download_item = GetDownload( |
962 profile(), include_incognito(), params->download_id); | 1097 profile(), include_incognito(), params->download_id); |
963 content::WebContents* web_contents = | 1098 content::WebContents* web_contents = |
964 dispatcher()->delegate()->GetAssociatedWebContents(); | 1099 dispatcher()->delegate()->GetAssociatedWebContents(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
999 int icon_size = kDefaultIconSize; | 1134 int icon_size = kDefaultIconSize; |
1000 if (options && options->size.get()) | 1135 if (options && options->size.get()) |
1001 icon_size = *options->size.get(); | 1136 icon_size = *options->size.get(); |
1002 DownloadItem* download_item = GetDownload( | 1137 DownloadItem* download_item = GetDownload( |
1003 profile(), include_incognito(), params->download_id); | 1138 profile(), include_incognito(), params->download_id); |
1004 if (!download_item || download_item->GetTargetFilePath().empty()) { | 1139 if (!download_item || download_item->GetTargetFilePath().empty()) { |
1005 error_ = download_extension_errors::kInvalidOperationError; | 1140 error_ = download_extension_errors::kInvalidOperationError; |
1006 return false; | 1141 return false; |
1007 } | 1142 } |
1008 // In-progress downloads return the intermediate filename for GetFullPath() | 1143 // In-progress downloads return the intermediate filename for GetFullPath() |
1009 // which doesn't have the final extension. Therefore we won't be able to | 1144 // which doesn't have the final extension. Therefore a good file icon can't be |
1010 // derive a good file icon for it. So we use GetTargetFilePath() instead. | 1145 // found, so use GetTargetFilePath() instead. |
1011 DCHECK(icon_extractor_.get()); | 1146 DCHECK(icon_extractor_.get()); |
1012 DCHECK(icon_size == 16 || icon_size == 32); | 1147 DCHECK(icon_size == 16 || icon_size == 32); |
1013 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( | 1148 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( |
1014 download_item->GetTargetFilePath(), | 1149 download_item->GetTargetFilePath(), |
1015 IconLoaderSizeFromPixelSize(icon_size), | 1150 IconLoaderSizeFromPixelSize(icon_size), |
1016 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); | 1151 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); |
1017 return true; | 1152 return true; |
1018 } | 1153 } |
1019 | 1154 |
1020 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { | 1155 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { |
1021 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1022 if (url.empty()) { | 1157 if (url.empty()) { |
1023 error_ = download_extension_errors::kIconNotFoundError; | 1158 error_ = download_extension_errors::kIconNotFoundError; |
1024 } else { | 1159 } else { |
1025 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); | 1160 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); |
1026 SetResult(base::Value::CreateStringValue(url)); | 1161 SetResult(base::Value::CreateStringValue(url)); |
1027 } | 1162 } |
1028 SendResponse(error_.empty()); | 1163 SendResponse(error_.empty()); |
1029 } | 1164 } |
1030 | 1165 |
| 1166 ExtensionDownloadsEventRouter::DeterminerId::DeterminerId( |
| 1167 const std::string& ext_id, |
| 1168 const std::string& sub_id) |
| 1169 : extension_id(ext_id), |
| 1170 sub_event_id(sub_id) { |
| 1171 } |
| 1172 |
| 1173 ExtensionDownloadsEventRouter::DeterminerId::~DeterminerId() {} |
| 1174 |
1031 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( | 1175 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
1032 Profile* profile, | 1176 Profile* profile, |
1033 DownloadManager* manager) | 1177 DownloadManager* manager) |
1034 : profile_(profile), | 1178 : profile_(profile), |
1035 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { | 1179 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { |
1036 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1037 DCHECK(profile_); | 1181 DCHECK(profile_); |
| 1182 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 1183 content::Source<Profile>(profile_)); |
1038 } | 1184 } |
1039 | 1185 |
1040 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | 1186 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
1041 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1042 } | 1188 } |
1043 | 1189 |
| 1190 // The method by which extensions hook into the filename determination process |
| 1191 // is based on the method by which the webRequest API allows extensions to hook |
| 1192 // into the resource loading process. Extensions that wish to play a part in |
| 1193 // the filename determination process call |
| 1194 // chrome.downloads.onDeterminingFilename.addListener, which secretly (see |
| 1195 // chrome/renderer/resources/extensions/downloads_custom_bindings.js) calls |
| 1196 // DownloadsInternalAddFilenameDeterminerFunction (see ../downloads_internal/), |
| 1197 // which adds the extension's ID to the profile's ExtensionDownloadsEventRouter |
| 1198 // (EDER). |
| 1199 // |
| 1200 // When a download's filename is being determined, |
| 1201 // ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone (CVRBD) passes |
| 1202 // 2 callbacks to EDER::OnDeterminingFilename (ODFD), which stores the |
| 1203 // callbacks in the item's ExtensionDownloadsEventRouterData (EDERD) along with |
| 1204 // all of the extension IDs that are listening for onDeterminingFilename events. |
| 1205 // ODFD dispatches chrome.downloads.onDeterminingFilename. |
| 1206 // |
| 1207 // When the extension's event handler returns, downloads_custom_bindings.js |
| 1208 // calls DownloadsInternalDetermineFilenameFunction::RunImpl, which notifies the |
| 1209 // item's EDERD. |
| 1210 // |
| 1211 // When the last extension's event handler returns, EDERD calls one of the two |
| 1212 // callbacks that CVRBD passed to ODFD, allowing CDMD to complete the filename |
| 1213 // determination process. If multiple extensions wish to override the filename, |
| 1214 // then the extension that was last installed wins; if multiple determiners |
| 1215 // within an extension compete, then the determiner that was last added wins. |
| 1216 |
| 1217 bool ExtensionDownloadsEventRouter::AddFilenameDeterminer( |
| 1218 Profile* profile, |
| 1219 const std::string& ext_id, |
| 1220 const std::string& sub_event_id) { |
| 1221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1222 // Only incognito/regular renderer processes receive onDeterminingFilename |
| 1223 // events for incognito/regular downloads. Do not automatically add this |
| 1224 // determiner to the other (incognito/regular) EDER; if the extension wants to |
| 1225 // listen for onDeterminingFilename in those extension renderer processes, |
| 1226 // then it will call addListener there, and |profile| will be |
| 1227 // incognito/regular for those addListener calls, so they will use the |
| 1228 // incognito/regular EDER. |
| 1229 ExtensionDownloadsEventRouter* router = |
| 1230 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); |
| 1231 if (!router) |
| 1232 return false; |
| 1233 for (DeterminerVector::const_iterator iter = router->determiners_.begin(); |
| 1234 iter != router->determiners_.end(); ++iter) { |
| 1235 if (iter->extension_id == ext_id) { |
| 1236 DCHECK_NE(iter->sub_event_id, sub_event_id); |
| 1237 } |
| 1238 if ((iter->extension_id == ext_id) && |
| 1239 (iter->sub_event_id == sub_event_id)) |
| 1240 return false; |
| 1241 } |
| 1242 router->determiners_.push_back(DeterminerId(ext_id, sub_event_id)); |
| 1243 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( |
| 1244 &ExtensionDownloadsEventRouter::GetInstallTime, |
| 1245 ext_id, |
| 1246 scoped_refptr<ExtensionInfoMap>( |
| 1247 extensions::ExtensionSystem::Get(profile)->info_map()), |
| 1248 &router->determiners_[router->determiners_.size() - 1].installed)); |
| 1249 return true; |
| 1250 } |
| 1251 |
| 1252 void ExtensionDownloadsEventRouter::GetInstallTime( |
| 1253 const std::string& ext_id, |
| 1254 ExtensionInfoMap* info_map, |
| 1255 base::Time* install_time) { |
| 1256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 1257 *install_time = info_map->GetInstallTime(ext_id); |
| 1258 } |
| 1259 |
| 1260 bool ExtensionDownloadsEventRouter::RemoveFilenameDeterminer( |
| 1261 Profile* profile, |
| 1262 const std::string& ext_id, |
| 1263 const std::string& sub_event_id) { |
| 1264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1265 ExtensionDownloadsEventRouter* router = |
| 1266 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); |
| 1267 for (DeterminerVector::iterator iter = router->determiners_.begin(); |
| 1268 iter != router->determiners_.end(); ++iter) { |
| 1269 if (iter->extension_id == ext_id && iter->sub_event_id == sub_event_id) { |
| 1270 router->determiners_.erase(iter); |
| 1271 return true; |
| 1272 } |
| 1273 } |
| 1274 DCHECK(false) << ext_id << " " << sub_event_id; |
| 1275 return false; |
| 1276 } |
| 1277 |
| 1278 void ExtensionDownloadsEventRouter::OnDeterminingFilename( |
| 1279 DownloadItem* item, |
| 1280 const FilePath& suggested_path, |
| 1281 const base::Closure& no_change, |
| 1282 const FilenameChangedCallback& change) { |
| 1283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1284 if (determiners_.empty()) { |
| 1285 no_change.Run(); |
| 1286 return; |
| 1287 } |
| 1288 |
| 1289 ExtensionDownloadsEventRouterData* data = |
| 1290 ExtensionDownloadsEventRouterData::Get(item); |
| 1291 data->ClearPendingDeterminers(); |
| 1292 data->set_filename_change_callbacks(no_change, change); |
| 1293 std::set<std::string> sub_events; |
| 1294 for (DeterminerVector::const_iterator iter = determiners_.begin(); |
| 1295 iter != determiners_.end(); ++iter) { |
| 1296 data->AddPendingDeterminer(iter->extension_id, |
| 1297 iter->sub_event_id, |
| 1298 iter->installed); |
| 1299 sub_events.insert(iter->sub_event_id); |
| 1300 } |
| 1301 std::string event_name( |
| 1302 extensions::event_names::kOnDownloadDeterminingFilename); |
| 1303 event_name += "/"; |
| 1304 for (std::set<std::string>::const_iterator iter = sub_events.begin(); |
| 1305 iter != sub_events.end(); ++iter) { |
| 1306 base::DictionaryValue* json = DownloadItemToJSON( |
| 1307 item, profile_->IsOffTheRecord()).release(); |
| 1308 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); |
| 1309 // If there's a listener in an incognito extension renderer, then it will |
| 1310 // have registered its own determiner in the incognito EDER, which will be |
| 1311 // called for incognito downloads. |
| 1312 DispatchEvent((event_name + (*iter)).c_str(), false, json); |
| 1313 } |
| 1314 } |
| 1315 |
| 1316 bool ExtensionDownloadsEventRouter::DetermineFilename( |
| 1317 Profile* profile, |
| 1318 bool include_incognito, |
| 1319 const std::string& ext_id, |
| 1320 const std::string& sub_event_id, |
| 1321 int download_id, |
| 1322 const FilePath& filename, |
| 1323 bool overwrite) { |
| 1324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1325 DownloadItem* item = GetDownloadIfInProgress( |
| 1326 profile, include_incognito, download_id); |
| 1327 if (!item) |
| 1328 return false; |
| 1329 ExtensionDownloadsEventRouterData* data = |
| 1330 ExtensionDownloadsEventRouterData::Get(item); |
| 1331 if (!data) |
| 1332 return false; |
| 1333 return data->DeterminerCallback(ext_id, sub_event_id, filename, overwrite); |
| 1334 } |
| 1335 |
| 1336 void ExtensionDownloadsEventRouter::Observe( |
| 1337 int type, |
| 1338 const content::NotificationSource& source, |
| 1339 const content::NotificationDetails& details) { |
| 1340 switch (type) { |
| 1341 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
| 1342 const extensions::Extension* extension = content::Details< |
| 1343 extensions::UnloadedExtensionInfo>(details)->extension; |
| 1344 // Remove this extension from |determiners_|. |
| 1345 for (DeterminerVector::iterator iter = determiners_.begin(); |
| 1346 iter != determiners_.end();) { |
| 1347 if (iter->extension_id == extension->id()) { |
| 1348 iter = determiners_.erase(iter); |
| 1349 } else { |
| 1350 ++iter; |
| 1351 } |
| 1352 } |
| 1353 // Notify any items that may be waiting for callbacks from this extension. |
| 1354 DownloadManager* manager = notifier_.GetManager(); |
| 1355 if (manager) { |
| 1356 DownloadManager::DownloadVector items; |
| 1357 manager->GetAllDownloads(&items); |
| 1358 for (DownloadManager::DownloadVector::const_iterator iter = |
| 1359 items.begin(); |
| 1360 iter != items.end(); ++iter) { |
| 1361 ExtensionDownloadsEventRouterData* data = |
| 1362 ExtensionDownloadsEventRouterData::Get(*iter); |
| 1363 if (data) |
| 1364 data->ExtensionUnloaded(extension->id()); |
| 1365 } |
| 1366 } |
| 1367 break; |
| 1368 } |
| 1369 default: |
| 1370 NOTREACHED(); |
| 1371 break; |
| 1372 } |
| 1373 } |
| 1374 |
| 1375 // That's all the methods that have to do with filename determination. The rest |
| 1376 // have to do with the other, less special events. |
| 1377 |
1044 void ExtensionDownloadsEventRouter::OnDownloadCreated( | 1378 void ExtensionDownloadsEventRouter::OnDownloadCreated( |
1045 DownloadManager* manager, DownloadItem* download_item) { | 1379 DownloadManager* manager, DownloadItem* download_item) { |
1046 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1047 if (download_item->IsTemporary()) | 1381 if (download_item->IsTemporary()) |
1048 return; | 1382 return; |
1049 | 1383 |
1050 scoped_ptr<base::DictionaryValue> json_item( | 1384 scoped_ptr<base::DictionaryValue> json_item( |
1051 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); | 1385 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
1052 DispatchEvent(extensions::event_names::kOnDownloadCreated, | 1386 DispatchEvent(extensions::event_names::kOnDownloadCreated, |
| 1387 true, |
1053 json_item->DeepCopy()); | 1388 json_item->DeepCopy()); |
1054 if (!ExtensionDownloadsEventRouterData::Get(download_item)) | 1389 if (!ExtensionDownloadsEventRouterData::Get(download_item)) |
1055 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); | 1390 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); |
1056 } | 1391 } |
1057 | 1392 |
1058 void ExtensionDownloadsEventRouter::OnDownloadUpdated( | 1393 void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
1059 DownloadManager* manager, DownloadItem* download_item) { | 1394 DownloadManager* manager, DownloadItem* download_item) { |
1060 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1061 if (download_item->IsTemporary()) | 1396 if (download_item->IsTemporary()) |
1062 return; | 1397 return; |
1063 | 1398 |
1064 ExtensionDownloadsEventRouterData* data = | 1399 ExtensionDownloadsEventRouterData* data = |
1065 ExtensionDownloadsEventRouterData::Get(download_item); | 1400 ExtensionDownloadsEventRouterData::Get(download_item); |
1066 if (!data) { | 1401 if (!data) { |
1067 // The download_item probably transitioned from temporary to not temporary. | 1402 // The download_item probably transitioned from temporary to not temporary. |
1068 OnDownloadCreated(manager, download_item); | 1403 OnDownloadCreated(manager, download_item); |
1069 return; | 1404 return; |
1070 } | 1405 } |
1071 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( | 1406 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( |
1072 download_item, profile_->IsOffTheRecord())); | 1407 download_item, profile_->IsOffTheRecord())); |
1073 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); | 1408 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
1074 delta->SetInteger(kIdKey, download_item->GetId()); | 1409 delta->SetInteger(kIdKey, download_item->GetId()); |
1075 std::set<std::string> new_fields; | 1410 std::set<std::string> new_fields; |
1076 bool changed = false; | 1411 bool changed = false; |
1077 | 1412 |
1078 // For each field in the new json representation of the download_item except | 1413 // For each field in the new json representation of the download_item except |
1079 // the bytesReceived field, if the field has changed from the previous old | 1414 // the bytesReceived field, if the field has changed from the previous old |
1080 // json, set the differences in the |delta| object and remember that something | 1415 // json, set the differences in the |delta| object and remember that something |
1081 // significant changed. | 1416 // significant changed. |
1082 for (base::DictionaryValue::Iterator iter(*new_json.get()); | 1417 for (base::DictionaryValue::Iterator iter(*new_json.get()); |
(...skipping 19 matching lines...) Expand all Loading... |
1102 if (new_fields.find(iter.key()) == new_fields.end()) { | 1437 if (new_fields.find(iter.key()) == new_fields.end()) { |
1103 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); | 1438 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); |
1104 changed = true; | 1439 changed = true; |
1105 } | 1440 } |
1106 } | 1441 } |
1107 | 1442 |
1108 // Update the OnChangedStat and dispatch the event if something significant | 1443 // Update the OnChangedStat and dispatch the event if something significant |
1109 // changed. Replace the stored json with the new json. | 1444 // changed. Replace the stored json with the new json. |
1110 data->OnItemUpdated(); | 1445 data->OnItemUpdated(); |
1111 if (changed) { | 1446 if (changed) { |
1112 DispatchEvent(extensions::event_names::kOnDownloadChanged, delta.release()); | 1447 DispatchEvent(extensions::event_names::kOnDownloadChanged, |
| 1448 true, |
| 1449 delta.release()); |
1113 data->OnChangedFired(); | 1450 data->OnChangedFired(); |
1114 } | 1451 } |
1115 data->set_json(new_json.Pass()); | 1452 data->set_json(new_json.Pass()); |
1116 } | 1453 } |
1117 | 1454 |
1118 void ExtensionDownloadsEventRouter::OnDownloadRemoved( | 1455 void ExtensionDownloadsEventRouter::OnDownloadRemoved( |
1119 DownloadManager* manager, DownloadItem* download_item) { | 1456 DownloadManager* manager, DownloadItem* download_item) { |
1120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1121 if (download_item->IsTemporary()) | 1458 if (download_item->IsTemporary()) |
1122 return; | 1459 return; |
1123 DispatchEvent(extensions::event_names::kOnDownloadErased, | 1460 DispatchEvent(extensions::event_names::kOnDownloadErased, |
| 1461 true, |
1124 base::Value::CreateIntegerValue(download_item->GetId())); | 1462 base::Value::CreateIntegerValue(download_item->GetId())); |
1125 } | 1463 } |
1126 | 1464 |
1127 void ExtensionDownloadsEventRouter::DispatchEvent( | 1465 void ExtensionDownloadsEventRouter::DispatchEvent( |
1128 const char* event_name, base::Value* arg) { | 1466 const char* event_name, bool include_incognito, base::Value* arg) { |
1129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1130 scoped_ptr<base::ListValue> args(new base::ListValue()); | 1468 scoped_ptr<base::ListValue> args(new base::ListValue()); |
1131 args->Append(arg); | 1469 args->Append(arg); |
1132 std::string json_args; | 1470 std::string json_args; |
1133 base::JSONWriter::Write(args.get(), &json_args); | 1471 base::JSONWriter::Write(args.get(), &json_args); |
1134 // There is a one EDER for each on-record Profile, and a separate EDER for | 1472 // There is a one EDER for each on-record Profile, and a separate EDER for |
1135 // each off-record Profile, so there is exactly one EDER for each | 1473 // each off-record Profile, so there is exactly one EDER for each |
1136 // DownloadManager. EDER only watches its own DM, so all the items that an | 1474 // DownloadManager. EDER only watches its own DM, so all the items that an |
1137 // EDER sees are either all on-record or all off-record. However, we want | 1475 // EDER sees are either all on-record or all off-record. However, extensions |
1138 // extensions in off-record contexts to see on-record items. So, if this EDER | 1476 // in off-record contexts should see on-record items. So, if this EDER is |
1139 // is watching an on-record DM, and there is a corresponding off-record | 1477 // watching an on-record DM, and there is a corresponding off-record Profile, |
1140 // Profile, then dispatch this event to both the on-record Profile and the | 1478 // then dispatch this event to both the on-record Profile and the off-record |
1141 // off-record Profile. There may or may not be an off-record Profile, so send | 1479 // Profile. There may or may not be an off-record Profile, so send a *copy* |
1142 // a *copy* of |args| to the off-record Profile, and Pass() |args| | 1480 // of |args| to the off-record Profile, and Pass() |args| to the Profile that |
1143 // to the Profile that we know is there. | 1481 // is certainly there. |
1144 if (profile_->HasOffTheRecordProfile() && | 1482 if (include_incognito && |
| 1483 profile_->HasOffTheRecordProfile() && |
1145 !profile_->IsOffTheRecord()) { | 1484 !profile_->IsOffTheRecord()) { |
1146 DispatchEventInternal( | 1485 DispatchEventInternal( |
1147 profile_->GetOffTheRecordProfile(), | 1486 profile_->GetOffTheRecordProfile(), |
1148 event_name, | 1487 event_name, |
1149 json_args, | 1488 json_args, |
1150 scoped_ptr<base::ListValue>(args->DeepCopy())); | 1489 scoped_ptr<base::ListValue>(args->DeepCopy())); |
1151 } | 1490 } |
1152 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); | 1491 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); |
1153 } | 1492 } |
OLD | NEW |