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

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 11574006: Implement chrome.downloads.onDeterminingFilename() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r180415 Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698