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

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

Powered by Google App Engine
This is Rietveld 408576698