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

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

Powered by Google App Engine
This is Rietveld 408576698