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