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

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

Powered by Google App Engine
This is Rietveld 408576698