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