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

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

Powered by Google App Engine
This is Rietveld 408576698