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

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: @r183850 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() &&
asanka 2013/02/22 18:55:48 "foo/" shouldn't be considered a valid filename ei
benjhayden 2013/02/22 20:43:23 I believe that the next line handles that case.
asanka 2013/02/22 21:22:29 For "foo/" BaseName() returns "foo".
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 determiners_.push_back(DeterminerInfo(
595 extension_id, sub_event_id, installed));
596 }
597
598 bool DeterminerCallback(
599 const std::string& extension_id,
600 int sub_event_id,
601 const base::FilePath& filename,
602 bool overwrite) {
603 bool filename_valid = ValidateFilename(filename);
604 bool found_info = false;
605 for (int index = 0; index < static_cast<int>(determiners_.size());
606 ++index) {
607 if ((determiners_[index].extension_id == extension_id) &&
608 (determiners_[index].sub_event_id == sub_event_id)) {
609 found_info = true;
asanka 2013/02/22 18:55:48 Curious: Is it possible for there to be more than
benjhayden 2013/02/22 20:43:23 I hope not. :-) See AddPendingDeterminer and searc
610 DCHECK(!determiners_[index].reported);
611 determiners_[index].reported = true;
612 if (!determiner_.extension_id.empty() &&
613 (determiners_[index].extension_id == determiner_.extension_id)) {
614 DCHECK_NE(determiners_[index].sub_event_id, determiner_.sub_event_id);
615 }
616 // Do not use filename if another determiner has already overridden the
617 // filename and they take precedence. Extensions that were installed
618 // later take precedence over previous extensions, and listeners that
619 // were added later take precedence over previous listeners.
620 if (filename_valid &&
621 (determiner_.extension_id.empty() ||
622 ((determiners_[index].extension_id == determiner_.extension_id) ?
623 (determiners_[index].sub_event_id > determiner_.sub_event_id) :
624 (determiners_[index].install_time > determiner_.install_time)))) {
625 determined_filename_ = filename;
626 determined_overwrite_ = overwrite;
627 determiner_ = determiners_[index];
628 }
629 }
630 }
631 if (!found_info)
632 return false;
633 CheckAllDeterminersCalled();
634 return filename.empty() || filename_valid;
635 }
636
567 private: 637 private:
638 struct DeterminerInfo {
639 DeterminerInfo();
640 DeterminerInfo(const std::string& e_id,
641 int sub_id,
642 const base::Time& installed);
643 ~DeterminerInfo();
644
645 std::string extension_id;
646 int sub_event_id;
647 base::Time install_time;
648 bool reported;
649 };
650 typedef std::vector<DeterminerInfo> DeterminerInfoVector;
651
568 static const char kKey[]; 652 static const char kKey[];
569 653
654 // This is safe to call even while not waiting for determiners to call back;
655 // in that case, the callbacks will be null so they won't be Run.
656 void CheckAllDeterminersCalled() {
657 for (DeterminerInfoVector::iterator iter = determiners_.begin();
658 iter != determiners_.end(); ++iter) {
659 if (!iter->reported)
660 return;
661 }
662 if (determined_filename_.empty()) {
663 if (!filename_no_change_.is_null())
664 filename_no_change_.Run();
665 } else {
666 if (!filename_change_.is_null())
667 filename_change_.Run(determined_filename_, determined_overwrite_);
668 }
669 ClearPendingDeterminers();
670 }
671
570 int updated_; 672 int updated_;
571 int changed_fired_; 673 int changed_fired_;
572 scoped_ptr<base::DictionaryValue> json_; 674 scoped_ptr<base::DictionaryValue> json_;
573 675
676 base::Closure filename_no_change_;
677 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_;
678
679 DeterminerInfoVector determiners_;
680
681 base::FilePath determined_filename_;
682 bool determined_overwrite_;
683 DeterminerInfo determiner_;
684
574 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); 685 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData);
575 }; 686 };
576 687
688 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo(
689 const std::string& e_id,
690 int sub_id,
691 const base::Time& installed)
692 : extension_id(e_id),
693 sub_event_id(sub_id),
694 install_time(installed),
695 reported(false) {
696 }
697
698 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo()
699 : reported(false) {
700 }
701
702 ExtensionDownloadsEventRouterData::DeterminerInfo::~DeterminerInfo() {}
703
577 const char ExtensionDownloadsEventRouterData::kKey[] = 704 const char ExtensionDownloadsEventRouterData::kKey[] =
578 "DownloadItem ExtensionDownloadsEventRouterData"; 705 "DownloadItem ExtensionDownloadsEventRouterData";
579 706
580 class ManagerDestructionObserver : public DownloadManager::Observer { 707 class ManagerDestructionObserver : public DownloadManager::Observer {
581 public: 708 public:
582 static void CheckForHistoryFilesRemoval(DownloadManager* manager) { 709 static void CheckForHistoryFilesRemoval(DownloadManager* manager) {
583 if (!manager) 710 if (!manager)
584 return; 711 return;
585 if (!manager_file_existence_last_checked_) 712 if (!manager_file_existence_last_checked_)
586 manager_file_existence_last_checked_ = 713 manager_file_existence_last_checked_ =
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 756
630 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver); 757 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver);
631 }; 758 };
632 759
633 std::map<DownloadManager*, ManagerDestructionObserver*>* 760 std::map<DownloadManager*, ManagerDestructionObserver*>*
634 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL; 761 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL;
635 762
636 } // namespace 763 } // namespace
637 764
638 DownloadsDownloadFunction::DownloadsDownloadFunction() {} 765 DownloadsDownloadFunction::DownloadsDownloadFunction() {}
766
639 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} 767 DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
640 768
641 bool DownloadsDownloadFunction::RunImpl() { 769 bool DownloadsDownloadFunction::RunImpl() {
642 scoped_ptr<extensions::api::downloads::Download::Params> params( 770 scoped_ptr<extensions::api::downloads::Download::Params> params(
643 extensions::api::downloads::Download::Params::Create(*args_)); 771 extensions::api::downloads::Download::Params::Create(*args_));
644 EXTENSION_FUNCTION_VALIDATE(params.get()); 772 EXTENSION_FUNCTION_VALIDATE(params.get());
645 const extensions::api::downloads::DownloadOptions& options = params->options; 773 const extensions::api::downloads::DownloadOptions& options = params->options;
646 GURL download_url(options.url); 774 GURL download_url(options.url);
647 if (!download_url.is_valid() || 775 if (!download_url.is_valid() ||
648 (!download_url.SchemeIs("data") && 776 (!download_url.SchemeIs("data") &&
(...skipping 16 matching lines...) Expand all
665 793
666 if (options.filename.get()) { 794 if (options.filename.get()) {
667 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of 795 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of
668 // std::strings. Can't get filename16 from options.ToValue() because that 796 // std::strings. Can't get filename16 from options.ToValue() because that
669 // converts it from std::string. 797 // converts it from std::string.
670 base::DictionaryValue* options_value = NULL; 798 base::DictionaryValue* options_value = NULL;
671 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); 799 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value));
672 string16 filename16; 800 string16 filename16;
673 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( 801 EXTENSION_FUNCTION_VALIDATE(options_value->GetString(
674 kFilenameKey, &filename16)); 802 kFilenameKey, &filename16));
675 if (!ValidateFilename(filename16)) { 803 #if defined(OS_WIN)
804 base::FilePath file_path(filename16);
805 #elif defined(OS_POSIX)
806 base::FilePath file_path(*options.filename.get());
807 #endif
808 if (!ValidateFilename(file_path) ||
809 (file_path.DirName().value() != base::FilePath::kCurrentDirectory)) {
676 error_ = download_extension_errors::kGenericError; 810 error_ = download_extension_errors::kGenericError;
677 return false; 811 return false;
678 } 812 }
679 // TODO(benjhayden) Ensure that this filename is interpreted as a path 813 // TODO(benjhayden) Ensure that this filename is interpreted as a path
680 // relative to the default downloads directory without allowing '..'. 814 // relative to the default downloads directory without allowing '..'.
681 download_params->set_suggested_name(filename16); 815 download_params->set_suggested_name(filename16);
682 } 816 }
683 817
684 if (options.save_as.get()) 818 if (options.save_as.get())
685 download_params->set_prompt(*options.save_as.get()); 819 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); 859 DCHECK_EQ(net::OK, error);
726 SetResult(base::Value::CreateIntegerValue(item->GetId())); 860 SetResult(base::Value::CreateIntegerValue(item->GetId()));
727 } else { 861 } else {
728 DCHECK_NE(net::OK, error); 862 DCHECK_NE(net::OK, error);
729 error_ = net::ErrorToString(error); 863 error_ = net::ErrorToString(error);
730 } 864 }
731 SendResponse(error_.empty()); 865 SendResponse(error_.empty());
732 } 866 }
733 867
734 DownloadsSearchFunction::DownloadsSearchFunction() {} 868 DownloadsSearchFunction::DownloadsSearchFunction() {}
869
735 DownloadsSearchFunction::~DownloadsSearchFunction() {} 870 DownloadsSearchFunction::~DownloadsSearchFunction() {}
736 871
737 bool DownloadsSearchFunction::RunImpl() { 872 bool DownloadsSearchFunction::RunImpl() {
738 scoped_ptr<extensions::api::downloads::Search::Params> params( 873 scoped_ptr<extensions::api::downloads::Search::Params> params(
739 extensions::api::downloads::Search::Params::Create(*args_)); 874 extensions::api::downloads::Search::Params::Create(*args_));
740 EXTENSION_FUNCTION_VALIDATE(params.get()); 875 EXTENSION_FUNCTION_VALIDATE(params.get());
741 DownloadManager* manager = NULL; 876 DownloadManager* manager = NULL;
742 DownloadManager* incognito_manager = NULL; 877 DownloadManager* incognito_manager = NULL;
743 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); 878 GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
744 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager); 879 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager);
(...skipping 17 matching lines...) Expand all
762 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( 897 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON(
763 *it, off_record)); 898 *it, off_record));
764 json_results->Append(json_item.release()); 899 json_results->Append(json_item.release());
765 } 900 }
766 SetResult(json_results); 901 SetResult(json_results);
767 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); 902 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH);
768 return true; 903 return true;
769 } 904 }
770 905
771 DownloadsPauseFunction::DownloadsPauseFunction() {} 906 DownloadsPauseFunction::DownloadsPauseFunction() {}
907
772 DownloadsPauseFunction::~DownloadsPauseFunction() {} 908 DownloadsPauseFunction::~DownloadsPauseFunction() {}
773 909
774 bool DownloadsPauseFunction::RunImpl() { 910 bool DownloadsPauseFunction::RunImpl() {
775 scoped_ptr<extensions::api::downloads::Pause::Params> params( 911 scoped_ptr<extensions::api::downloads::Pause::Params> params(
776 extensions::api::downloads::Pause::Params::Create(*args_)); 912 extensions::api::downloads::Pause::Params::Create(*args_));
777 EXTENSION_FUNCTION_VALIDATE(params.get()); 913 EXTENSION_FUNCTION_VALIDATE(params.get());
778 DownloadItem* download_item = GetDownloadIfInProgress( 914 DownloadItem* download_item = GetDownloadIfInProgress(
779 profile(), include_incognito(), params->download_id); 915 profile(), include_incognito(), params->download_id);
780 if (download_item == NULL) { 916 if (download_item == NULL) {
781 // This could be due to an invalid download ID, or it could be due to the 917 // This could be due to an invalid download ID, or it could be due to the
782 // download not being currently active. 918 // download not being currently active.
783 error_ = download_extension_errors::kInvalidOperationError; 919 error_ = download_extension_errors::kInvalidOperationError;
784 } else { 920 } else {
785 // If the item is already paused, this is a no-op and the 921 // If the item is already paused, this is a no-op and the
786 // operation will silently succeed. 922 // operation will silently succeed.
787 download_item->Pause(); 923 download_item->Pause();
788 } 924 }
789 if (error_.empty()) 925 if (error_.empty())
790 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE); 926 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE);
791 return error_.empty(); 927 return error_.empty();
792 } 928 }
793 929
794 DownloadsResumeFunction::DownloadsResumeFunction() {} 930 DownloadsResumeFunction::DownloadsResumeFunction() {}
931
795 DownloadsResumeFunction::~DownloadsResumeFunction() {} 932 DownloadsResumeFunction::~DownloadsResumeFunction() {}
796 933
797 bool DownloadsResumeFunction::RunImpl() { 934 bool DownloadsResumeFunction::RunImpl() {
798 scoped_ptr<extensions::api::downloads::Resume::Params> params( 935 scoped_ptr<extensions::api::downloads::Resume::Params> params(
799 extensions::api::downloads::Resume::Params::Create(*args_)); 936 extensions::api::downloads::Resume::Params::Create(*args_));
800 EXTENSION_FUNCTION_VALIDATE(params.get()); 937 EXTENSION_FUNCTION_VALIDATE(params.get());
801 DownloadItem* download_item = GetDownloadIfInProgress( 938 DownloadItem* download_item = GetDownloadIfInProgress(
802 profile(), include_incognito(), params->download_id); 939 profile(), include_incognito(), params->download_id);
803 if (download_item == NULL) { 940 if (download_item == NULL) {
804 // This could be due to an invalid download ID, or it could be due to the 941 // This could be due to an invalid download ID, or it could be due to the
805 // download not being currently active. 942 // download not being currently active.
806 error_ = download_extension_errors::kInvalidOperationError; 943 error_ = download_extension_errors::kInvalidOperationError;
807 } else { 944 } else {
808 // Note that if the item isn't paused, this will be a no-op, and 945 // 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. 946 // the extension call will seem successful.
810 download_item->Resume(); 947 download_item->Resume();
811 } 948 }
812 if (error_.empty()) 949 if (error_.empty())
813 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); 950 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME);
814 return error_.empty(); 951 return error_.empty();
815 } 952 }
816 953
817 DownloadsCancelFunction::DownloadsCancelFunction() {} 954 DownloadsCancelFunction::DownloadsCancelFunction() {}
955
818 DownloadsCancelFunction::~DownloadsCancelFunction() {} 956 DownloadsCancelFunction::~DownloadsCancelFunction() {}
819 957
820 bool DownloadsCancelFunction::RunImpl() { 958 bool DownloadsCancelFunction::RunImpl() {
821 scoped_ptr<extensions::api::downloads::Resume::Params> params( 959 scoped_ptr<extensions::api::downloads::Resume::Params> params(
822 extensions::api::downloads::Resume::Params::Create(*args_)); 960 extensions::api::downloads::Resume::Params::Create(*args_));
823 EXTENSION_FUNCTION_VALIDATE(params.get()); 961 EXTENSION_FUNCTION_VALIDATE(params.get());
824 DownloadItem* download_item = GetDownloadIfInProgress( 962 DownloadItem* download_item = GetDownloadIfInProgress(
825 profile(), include_incognito(), params->download_id); 963 profile(), include_incognito(), params->download_id);
826 if (download_item != NULL) 964 if (download_item != NULL)
827 download_item->Cancel(true); 965 download_item->Cancel(true);
828 // |download_item| can be NULL if the download ID was invalid or if the 966 // |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 967 // download is not currently active. Either way, it's not a failure.
830 // failure.
831 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); 968 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL);
832 return true; 969 return true;
833 } 970 }
834 971
835 DownloadsEraseFunction::DownloadsEraseFunction() {} 972 DownloadsEraseFunction::DownloadsEraseFunction() {}
973
836 DownloadsEraseFunction::~DownloadsEraseFunction() {} 974 DownloadsEraseFunction::~DownloadsEraseFunction() {}
837 975
838 bool DownloadsEraseFunction::RunImpl() { 976 bool DownloadsEraseFunction::RunImpl() {
839 scoped_ptr<extensions::api::downloads::Erase::Params> params( 977 scoped_ptr<extensions::api::downloads::Erase::Params> params(
840 extensions::api::downloads::Erase::Params::Create(*args_)); 978 extensions::api::downloads::Erase::Params::Create(*args_));
841 EXTENSION_FUNCTION_VALIDATE(params.get()); 979 EXTENSION_FUNCTION_VALIDATE(params.get());
842 DownloadManager* manager = NULL; 980 DownloadManager* manager = NULL;
843 DownloadManager* incognito_manager = NULL; 981 DownloadManager* incognito_manager = NULL;
844 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); 982 GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
845 DownloadQuery::DownloadVector results; 983 DownloadQuery::DownloadVector results;
846 RunDownloadQuery(params->query, 984 RunDownloadQuery(params->query,
847 manager, 985 manager,
848 incognito_manager, 986 incognito_manager,
849 &error_, 987 &error_,
850 &results); 988 &results);
851 if (!error_.empty()) 989 if (!error_.empty())
852 return false; 990 return false;
853 base::ListValue* json_results = new base::ListValue(); 991 base::ListValue* json_results = new base::ListValue();
854 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); 992 for (DownloadManager::DownloadVector::const_iterator it = results.begin();
855 it != results.end(); ++it) { 993 it != results.end(); ++it) {
856 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); 994 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId()));
857 (*it)->Remove(); 995 (*it)->Remove();
858 } 996 }
859 SetResult(json_results); 997 SetResult(json_results);
860 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); 998 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE);
861 return true; 999 return true;
862 } 1000 }
863 1001
864 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() {} 1002 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {}
865 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {}
866 1003
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() {} 1004 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
879 1005
880 bool DownloadsAcceptDangerFunction::RunImpl() { 1006 bool DownloadsAcceptDangerFunction::RunImpl() {
881 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( 1007 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params(
882 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); 1008 extensions::api::downloads::AcceptDanger::Params::Create(*args_));
883 EXTENSION_FUNCTION_VALIDATE(params.get()); 1009 EXTENSION_FUNCTION_VALIDATE(params.get());
884 DownloadItem* download_item = GetDownloadIfInProgress( 1010 DownloadItem* download_item = GetDownloadIfInProgress(
885 profile(), include_incognito(), params->download_id); 1011 profile(), include_incognito(), params->download_id);
886 content::WebContents* web_contents = 1012 content::WebContents* web_contents =
887 dispatcher()->delegate()->GetAssociatedWebContents(); 1013 dispatcher()->delegate()->GetAssociatedWebContents();
(...skipping 23 matching lines...) Expand all
911 if (accept) { 1037 if (accept) {
912 DownloadItem* download_item = GetDownloadIfInProgress( 1038 DownloadItem* download_item = GetDownloadIfInProgress(
913 profile(), include_incognito(), download_id); 1039 profile(), include_incognito(), download_id);
914 if (download_item) 1040 if (download_item)
915 download_item->DangerousDownloadValidated(); 1041 download_item->DangerousDownloadValidated();
916 } 1042 }
917 SendResponse(error_.empty()); 1043 SendResponse(error_.empty());
918 } 1044 }
919 1045
920 DownloadsShowFunction::DownloadsShowFunction() {} 1046 DownloadsShowFunction::DownloadsShowFunction() {}
1047
921 DownloadsShowFunction::~DownloadsShowFunction() {} 1048 DownloadsShowFunction::~DownloadsShowFunction() {}
922 1049
923 bool DownloadsShowFunction::RunImpl() { 1050 bool DownloadsShowFunction::RunImpl() {
924 scoped_ptr<extensions::api::downloads::Show::Params> params( 1051 scoped_ptr<extensions::api::downloads::Show::Params> params(
925 extensions::api::downloads::Show::Params::Create(*args_)); 1052 extensions::api::downloads::Show::Params::Create(*args_));
926 EXTENSION_FUNCTION_VALIDATE(params.get()); 1053 EXTENSION_FUNCTION_VALIDATE(params.get());
927 DownloadItem* download_item = GetDownload( 1054 DownloadItem* download_item = GetDownload(
928 profile(), include_incognito(), params->download_id); 1055 profile(), include_incognito(), params->download_id);
929 if (!download_item) { 1056 if (!download_item) {
930 error_ = download_extension_errors::kInvalidOperationError; 1057 error_ = download_extension_errors::kInvalidOperationError;
931 return false; 1058 return false;
932 } 1059 }
933 download_item->ShowDownloadInShell(); 1060 download_item->ShowDownloadInShell();
934 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); 1061 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW);
935 return true; 1062 return true;
936 } 1063 }
937 1064
938 DownloadsOpenFunction::DownloadsOpenFunction() {} 1065 DownloadsOpenFunction::DownloadsOpenFunction() {}
1066
939 DownloadsOpenFunction::~DownloadsOpenFunction() {} 1067 DownloadsOpenFunction::~DownloadsOpenFunction() {}
940 1068
941 bool DownloadsOpenFunction::RunImpl() { 1069 bool DownloadsOpenFunction::RunImpl() {
942 scoped_ptr<extensions::api::downloads::Open::Params> params( 1070 scoped_ptr<extensions::api::downloads::Open::Params> params(
943 extensions::api::downloads::Open::Params::Create(*args_)); 1071 extensions::api::downloads::Open::Params::Create(*args_));
944 EXTENSION_FUNCTION_VALIDATE(params.get()); 1072 EXTENSION_FUNCTION_VALIDATE(params.get());
945 DownloadItem* download_item = GetDownload( 1073 DownloadItem* download_item = GetDownload(
946 profile(), include_incognito(), params->download_id); 1074 profile(), include_incognito(), params->download_id);
947 if (!download_item || !download_item->IsComplete()) { 1075 if (!download_item || !download_item->IsComplete()) {
948 error_ = download_extension_errors::kInvalidOperationError; 1076 error_ = download_extension_errors::kInvalidOperationError;
949 return false; 1077 return false;
950 } 1078 }
951 download_item->OpenDownload(); 1079 download_item->OpenDownload();
952 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); 1080 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN);
953 return true; 1081 return true;
954 } 1082 }
955 1083
956 DownloadsDragFunction::DownloadsDragFunction() {} 1084 DownloadsDragFunction::DownloadsDragFunction() {}
1085
957 DownloadsDragFunction::~DownloadsDragFunction() {} 1086 DownloadsDragFunction::~DownloadsDragFunction() {}
958 1087
959 bool DownloadsDragFunction::RunImpl() { 1088 bool DownloadsDragFunction::RunImpl() {
960 scoped_ptr<extensions::api::downloads::Drag::Params> params( 1089 scoped_ptr<extensions::api::downloads::Drag::Params> params(
961 extensions::api::downloads::Drag::Params::Create(*args_)); 1090 extensions::api::downloads::Drag::Params::Create(*args_));
962 EXTENSION_FUNCTION_VALIDATE(params.get()); 1091 EXTENSION_FUNCTION_VALIDATE(params.get());
963 DownloadItem* download_item = GetDownload( 1092 DownloadItem* download_item = GetDownload(
964 profile(), include_incognito(), params->download_id); 1093 profile(), include_incognito(), params->download_id);
965 content::WebContents* web_contents = 1094 content::WebContents* web_contents =
966 dispatcher()->delegate()->GetAssociatedWebContents(); 1095 dispatcher()->delegate()->GetAssociatedWebContents();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 int icon_size = kDefaultIconSize; 1130 int icon_size = kDefaultIconSize;
1002 if (options && options->size.get()) 1131 if (options && options->size.get())
1003 icon_size = *options->size.get(); 1132 icon_size = *options->size.get();
1004 DownloadItem* download_item = GetDownload( 1133 DownloadItem* download_item = GetDownload(
1005 profile(), include_incognito(), params->download_id); 1134 profile(), include_incognito(), params->download_id);
1006 if (!download_item || download_item->GetTargetFilePath().empty()) { 1135 if (!download_item || download_item->GetTargetFilePath().empty()) {
1007 error_ = download_extension_errors::kInvalidOperationError; 1136 error_ = download_extension_errors::kInvalidOperationError;
1008 return false; 1137 return false;
1009 } 1138 }
1010 // In-progress downloads return the intermediate filename for GetFullPath() 1139 // In-progress downloads return the intermediate filename for GetFullPath()
1011 // which doesn't have the final extension. Therefore we won't be able to 1140 // 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. 1141 // found, so use GetTargetFilePath() instead.
1013 DCHECK(icon_extractor_.get()); 1142 DCHECK(icon_extractor_.get());
1014 DCHECK(icon_size == 16 || icon_size == 32); 1143 DCHECK(icon_size == 16 || icon_size == 32);
1015 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( 1144 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath(
1016 download_item->GetTargetFilePath(), 1145 download_item->GetTargetFilePath(),
1017 IconLoaderSizeFromPixelSize(icon_size), 1146 IconLoaderSizeFromPixelSize(icon_size),
1018 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); 1147 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
1019 return true; 1148 return true;
1020 } 1149 }
1021 1150
1022 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { 1151 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) {
1023 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1024 if (url.empty()) { 1153 if (url.empty()) {
1025 error_ = download_extension_errors::kIconNotFoundError; 1154 error_ = download_extension_errors::kIconNotFoundError;
1026 } else { 1155 } else {
1027 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); 1156 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON);
1028 SetResult(base::Value::CreateStringValue(url)); 1157 SetResult(base::Value::CreateStringValue(url));
1029 } 1158 }
1030 SendResponse(error_.empty()); 1159 SendResponse(error_.empty());
1031 } 1160 }
1032 1161
1162 ExtensionDownloadsEventRouter::DeterminerId::DeterminerId(
1163 const std::string& ext_id,
1164 int sub_id,
1165 bool incognito,
1166 const base::Time& install)
1167 : extension_id(ext_id),
1168 sub_event_id(sub_id),
1169 include_incognito(incognito),
1170 installed(install) {
1171 }
1172
1173 ExtensionDownloadsEventRouter::DeterminerId::~DeterminerId() {}
1174
1033 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( 1175 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
1034 Profile* profile, 1176 Profile* profile,
1035 DownloadManager* manager) 1177 DownloadManager* manager)
1036 : profile_(profile), 1178 : profile_(profile),
1037 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { 1179 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) {
1038 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1039 DCHECK(profile_); 1181 DCHECK(profile_);
1182 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
1183 content::Source<Profile>(profile_));
1040 } 1184 }
1041 1185
1042 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { 1186 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
1043 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1044 } 1188 }
1045 1189
1190 // The method by which extensions hook into the filename determination process
1191 // is based on the method by which the webRequest API allows extensions to hook
1192 // into the resource loading process. Extensions that wish to play a part in
1193 // the filename determination process call
1194 // chrome.downloads.onDeterminingFilename.addListener, which secretly (see
1195 // chrome/renderer/resources/extensions/downloads_custom_bindings.js) calls
1196 // DownloadsInternalAddFilenameDeterminerFunction (see ../downloads_internal/),
1197 // which adds the extension's ID to the profile's ExtensionDownloadsEventRouter
1198 // (EDER).
1199 //
1200 // When a download's filename is being determined,
1201 // ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone (CVRBD) passes
1202 // 2 callbacks to EDER::OnDeterminingFilename (ODFD), which stores the
1203 // callbacks in the item's ExtensionDownloadsEventRouterData (EDERD) along with
1204 // all of the extension IDs that are listening for onDeterminingFilename events.
1205 // ODFD dispatches chrome.downloads.onDeterminingFilename.
1206 //
1207 // When the extension's event handler returns, downloads_custom_bindings.js
1208 // calls DownloadsInternalDetermineFilenameFunction::RunImpl, which notifies the
1209 // item's EDERD.
1210 //
1211 // When the last extension's event handler returns, EDERD calls one of the two
1212 // callbacks that CVRBD passed to ODFD, allowing CDMD to complete the filename
1213 // determination process. If multiple extensions wish to override the filename,
1214 // then the extension that was last installed wins; if multiple determiners
1215 // within an extension compete, then the determiner that was last added wins.
1216
1217 bool ExtensionDownloadsEventRouter::AddFilenameDeterminer(
1218 Profile* profile,
1219 bool include_incognito,
1220 const std::string& ext_id,
1221 int sub_event_id) {
1222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1223 // Only incognito/regular renderer processes receive onDeterminingFilename
1224 // events for incognito/regular downloads. Do not automatically add this
1225 // determiner to the other (incognito/regular) EDER; if the extension wants to
1226 // listen for onDeterminingFilename in those extension renderer processes,
1227 // then it will call addListener there, and |profile| will be
1228 // incognito/regular for those addListener calls, so they will use the
1229 // incognito/regular EDER.
1230 ExtensionDownloadsEventRouter* router =
1231 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter();
1232 if (!router)
1233 return false;
1234 for (DeterminerVector::const_iterator iter = router->determiners_.begin();
1235 iter != router->determiners_.end(); ++iter) {
1236 if (iter->extension_id == ext_id) {
1237 DCHECK_NE(iter->sub_event_id, sub_event_id);
1238 }
1239 if ((iter->extension_id == ext_id) &&
1240 (iter->sub_event_id == sub_event_id))
1241 return false;
1242 }
1243 base::Time installed = extensions::ExtensionSystem::Get(
1244 profile)->extension_service()->extension_prefs()->GetInstallTime(ext_id);
1245 router->determiners_.push_back(DeterminerId(
1246 ext_id, sub_event_id, include_incognito, installed));
1247 return true;
1248 }
1249
1250 bool ExtensionDownloadsEventRouter::RemoveFilenameDeterminer(
1251 Profile* profile,
1252 const std::string& ext_id,
1253 int sub_event_id) {
1254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1255 ExtensionDownloadsEventRouter* router =
1256 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter();
1257 for (DeterminerVector::iterator iter = router->determiners_.begin();
1258 iter != router->determiners_.end(); ++iter) {
1259 if (iter->extension_id == ext_id && iter->sub_event_id == sub_event_id) {
1260 router->determiners_.erase(iter);
1261 // Notify any items that may be waiting for callbacks from this
1262 // determiner.
1263 DownloadManager* manager = router->notifier_.GetManager();
1264 if (manager) {
1265 DownloadManager::DownloadVector items;
1266 manager->GetAllDownloads(&items);
1267 for (DownloadManager::DownloadVector::const_iterator iter =
1268 items.begin();
1269 iter != items.end(); ++iter) {
1270 ExtensionDownloadsEventRouterData* data =
1271 ExtensionDownloadsEventRouterData::Get(*iter);
1272 if (data)
1273 data->DeterminerRemoved(ext_id, sub_event_id);
1274 }
1275 }
1276 return true;
1277 }
1278 }
1279 DCHECK(false) << ext_id << " " << sub_event_id;
1280 return false;
1281 }
1282
1283 void ExtensionDownloadsEventRouter::OnDeterminingFilename(
1284 DownloadItem* item,
1285 const base::FilePath& suggested_path,
1286 const base::Closure& no_change,
1287 const FilenameChangedCallback& change) {
1288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1289 bool any_determiners = false;
1290
1291 ExtensionDownloadsEventRouterData* data =
1292 ExtensionDownloadsEventRouterData::Get(item);
1293 data->ClearPendingDeterminers();
asanka 2013/02/22 18:55:48 Is it possible for there to be a pending determine
benjhayden 2013/02/22 20:43:23 Yep, Randy suggested clearing pending determiners
1294 data->set_filename_change_callbacks(no_change, change);
1295 std::set<int> sub_events;
1296 for (DeterminerVector::const_iterator iter = determiners_.begin();
1297 iter != determiners_.end(); ++iter) {
1298 data->AddPendingDeterminer(iter->extension_id,
1299 iter->sub_event_id,
1300 iter->installed);
1301 sub_events.insert(iter->sub_event_id);
1302 any_determiners = true;
1303 }
1304
1305 if (profile_->IsOffTheRecord()) {
1306 // If this DownloadItem is incognito and there are any
1307 // incognito-spanning-mode extensions registered in the on-record EDER, then
1308 // dispatch to them and wait for them as well.
1309 ExtensionDownloadsEventRouter* router =
1310 DownloadServiceFactory::GetForProfile(
1311 profile_->GetOriginalProfile())->GetExtensionEventRouter();
1312 for (DeterminerVector::const_iterator iter = router->determiners_.begin();
1313 iter != router->determiners_.end(); ++iter) {
1314 if (iter->include_incognito) {
1315 data->AddPendingDeterminer(iter->extension_id,
1316 iter->sub_event_id,
1317 iter->installed);
1318 sub_events.insert(iter->sub_event_id);
1319 any_determiners = true;
1320 }
1321 }
1322 }
1323
1324 std::string event_name(
1325 extensions::event_names::kOnDownloadDeterminingFilename);
1326 event_name += "/";
1327 for (std::set<int>::const_iterator iter = sub_events.begin();
1328 iter != sub_events.end(); ++iter) {
1329 base::DictionaryValue* json = DownloadItemToJSON(
1330 item, profile_->IsOffTheRecord()).release();
1331 json->SetString(kFilenameKey, suggested_path.LossyDisplayName());
1332 // If there's a listener in an incognito extension renderer, then it will
1333 // have registered its own determiner in the incognito EDER, which will be
1334 // called for incognito downloads.
1335 DispatchEvent((event_name + base::IntToString(*iter)).c_str(), false, json);
1336 }
1337
1338 if (!any_determiners) {
1339 no_change.Run();
1340 return;
1341 }
1342 }
1343
1344 bool ExtensionDownloadsEventRouter::DetermineFilename(
1345 Profile* profile,
1346 bool include_incognito,
1347 const std::string& ext_id,
1348 int sub_event_id,
1349 int download_id,
1350 const base::FilePath& filename,
1351 bool overwrite) {
1352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1353 DownloadItem* item = GetDownloadIfInProgress(
1354 profile, include_incognito, download_id);
1355 if (!item)
1356 return false;
1357 ExtensionDownloadsEventRouterData* data =
1358 ExtensionDownloadsEventRouterData::Get(item);
1359 if (!data)
1360 return false;
1361 return data->DeterminerCallback(ext_id, sub_event_id, filename, overwrite);
1362 }
1363
1364 void ExtensionDownloadsEventRouter::Observe(
1365 int type,
1366 const content::NotificationSource& source,
1367 const content::NotificationDetails& details) {
1368 switch (type) {
1369 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
1370 const extensions::Extension* extension = content::Details<
1371 extensions::UnloadedExtensionInfo>(details)->extension;
1372 // Remove this extension from |determiners_|.
1373 for (DeterminerVector::iterator iter = determiners_.begin();
1374 iter != determiners_.end();) {
1375 if (iter->extension_id == extension->id()) {
1376 iter = determiners_.erase(iter);
1377 } else {
1378 ++iter;
1379 }
1380 }
1381 // Notify any items that may be waiting for callbacks from this extension.
1382 DownloadManager* manager = notifier_.GetManager();
1383 if (manager) {
1384 DownloadManager::DownloadVector items;
1385 manager->GetAllDownloads(&items);
1386 for (DownloadManager::DownloadVector::const_iterator iter =
1387 items.begin();
1388 iter != items.end(); ++iter) {
1389 ExtensionDownloadsEventRouterData* data =
1390 ExtensionDownloadsEventRouterData::Get(*iter);
1391 if (data)
1392 data->ExtensionUnloaded(extension->id());
1393 }
1394 }
1395 break;
1396 }
1397 default:
1398 NOTREACHED();
1399 break;
1400 }
1401 }
1402
1403 // That's all the methods that have to do with filename determination. The rest
1404 // have to do with the other, less special events.
1405
1046 void ExtensionDownloadsEventRouter::OnDownloadCreated( 1406 void ExtensionDownloadsEventRouter::OnDownloadCreated(
1047 DownloadManager* manager, DownloadItem* download_item) { 1407 DownloadManager* manager, DownloadItem* download_item) {
1048 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1049 if (download_item->IsTemporary()) 1409 if (download_item->IsTemporary())
1050 return; 1410 return;
1051 1411
1052 scoped_ptr<base::DictionaryValue> json_item( 1412 scoped_ptr<base::DictionaryValue> json_item(
1053 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); 1413 DownloadItemToJSON(download_item, profile_->IsOffTheRecord()));
1054 DispatchEvent(extensions::event_names::kOnDownloadCreated, 1414 DispatchEvent(extensions::event_names::kOnDownloadCreated,
1415 true,
1055 json_item->DeepCopy()); 1416 json_item->DeepCopy());
1056 if (!ExtensionDownloadsEventRouterData::Get(download_item)) 1417 if (!ExtensionDownloadsEventRouterData::Get(download_item))
1057 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); 1418 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass());
1058 } 1419 }
1059 1420
1060 void ExtensionDownloadsEventRouter::OnDownloadUpdated( 1421 void ExtensionDownloadsEventRouter::OnDownloadUpdated(
1061 DownloadManager* manager, DownloadItem* download_item) { 1422 DownloadManager* manager, DownloadItem* download_item) {
1062 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1063 if (download_item->IsTemporary()) 1424 if (download_item->IsTemporary())
1064 return; 1425 return;
1065 1426
1066 ExtensionDownloadsEventRouterData* data = 1427 ExtensionDownloadsEventRouterData* data =
1067 ExtensionDownloadsEventRouterData::Get(download_item); 1428 ExtensionDownloadsEventRouterData::Get(download_item);
1068 if (!data) { 1429 if (!data) {
1069 // The download_item probably transitioned from temporary to not temporary. 1430 // The download_item probably transitioned from temporary to not temporary.
1070 OnDownloadCreated(manager, download_item); 1431 OnDownloadCreated(manager, download_item);
1071 return; 1432 return;
1072 } 1433 }
1073 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( 1434 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(
1074 download_item, profile_->IsOffTheRecord())); 1435 download_item, profile_->IsOffTheRecord()));
1075 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); 1436 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue());
1076 delta->SetInteger(kIdKey, download_item->GetId()); 1437 delta->SetInteger(kIdKey, download_item->GetId());
1077 std::set<std::string> new_fields; 1438 std::set<std::string> new_fields;
1078 bool changed = false; 1439 bool changed = false;
1079 1440
1080 // For each field in the new json representation of the download_item except 1441 // 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 1442 // 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 1443 // json, set the differences in the |delta| object and remember that something
1083 // significant changed. 1444 // significant changed.
1084 for (base::DictionaryValue::Iterator iter(*new_json.get()); 1445 for (base::DictionaryValue::Iterator iter(*new_json.get());
(...skipping 19 matching lines...) Expand all
1104 if (new_fields.find(iter.key()) == new_fields.end()) { 1465 if (new_fields.find(iter.key()) == new_fields.end()) {
1105 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); 1466 delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
1106 changed = true; 1467 changed = true;
1107 } 1468 }
1108 } 1469 }
1109 1470
1110 // Update the OnChangedStat and dispatch the event if something significant 1471 // Update the OnChangedStat and dispatch the event if something significant
1111 // changed. Replace the stored json with the new json. 1472 // changed. Replace the stored json with the new json.
1112 data->OnItemUpdated(); 1473 data->OnItemUpdated();
1113 if (changed) { 1474 if (changed) {
1114 DispatchEvent(extensions::event_names::kOnDownloadChanged, delta.release()); 1475 DispatchEvent(extensions::event_names::kOnDownloadChanged,
1476 true,
1477 delta.release());
1115 data->OnChangedFired(); 1478 data->OnChangedFired();
1116 } 1479 }
1117 data->set_json(new_json.Pass()); 1480 data->set_json(new_json.Pass());
1118 } 1481 }
1119 1482
1120 void ExtensionDownloadsEventRouter::OnDownloadRemoved( 1483 void ExtensionDownloadsEventRouter::OnDownloadRemoved(
1121 DownloadManager* manager, DownloadItem* download_item) { 1484 DownloadManager* manager, DownloadItem* download_item) {
1122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1123 if (download_item->IsTemporary()) 1486 if (download_item->IsTemporary())
1124 return; 1487 return;
1125 DispatchEvent(extensions::event_names::kOnDownloadErased, 1488 DispatchEvent(extensions::event_names::kOnDownloadErased,
1489 true,
1126 base::Value::CreateIntegerValue(download_item->GetId())); 1490 base::Value::CreateIntegerValue(download_item->GetId()));
1127 } 1491 }
1128 1492
1129 void ExtensionDownloadsEventRouter::DispatchEvent( 1493 void ExtensionDownloadsEventRouter::DispatchEvent(
1130 const char* event_name, base::Value* arg) { 1494 const char* event_name, bool include_incognito, base::Value* arg) {
1131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1495 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1496 if (!extensions::ExtensionSystem::Get(profile_)->event_router())
1497 return;
1132 scoped_ptr<base::ListValue> args(new base::ListValue()); 1498 scoped_ptr<base::ListValue> args(new base::ListValue());
1133 args->Append(arg); 1499 args->Append(arg);
1134 std::string json_args; 1500 std::string json_args;
1135 base::JSONWriter::Write(args.get(), &json_args); 1501 base::JSONWriter::Write(args.get(), &json_args);
1136 // There is a one EDER for each on-record Profile, and a separate EDER for 1502 scoped_ptr<extensions::Event> event(new extensions::Event(
1137 // each off-record Profile, so there is exactly one EDER for each 1503 event_name, args.Pass()));
1138 // DownloadManager. EDER only watches its own DM, so all the items that an 1504 // "restrict_to_profile" is not smart enough to avoid sharing off-record
1139 // EDER sees are either all on-record or all off-record. However, we want 1505 // events with on-record extension renderers.
Matt Perry 2013/02/22 01:43:43 This comment is a bit cryptic to me. The main qui
benjhayden 2013/02/22 20:43:23 Done.
1140 // extensions in off-record contexts to see on-record items. So, if this EDER 1506 event->restrict_to_profile =
1141 // is watching an on-record DM, and there is a corresponding off-record 1507 (include_incognito && !profile_->IsOffTheRecord()) ? NULL : profile_;
1142 // Profile, then dispatch this event to both the on-record Profile and the 1508 extensions::ExtensionSystem::Get(profile_)->event_router()->
1143 // off-record Profile. There may or may not be an off-record Profile, so send 1509 BroadcastEvent(event.Pass());
1144 // a *copy* of |args| to the off-record Profile, and Pass() |args| 1510 ExtensionDownloadsEventRouter::DownloadsNotificationSource
Matt Perry 2013/02/22 01:43:43 nit: you're already in this scope so you can drop
benjhayden 2013/02/22 20:43:23 Done.
1145 // to the Profile that we know is there. 1511 notification_source;
1146 if (profile_->HasOffTheRecordProfile() && 1512 notification_source.event_name = event_name;
1147 !profile_->IsOffTheRecord()) { 1513 notification_source.profile = profile_;
1148 DispatchEventInternal( 1514 content::Source<ExtensionDownloadsEventRouter::DownloadsNotificationSource>
Matt Perry 2013/02/22 01:43:43 same here
benjhayden 2013/02/22 20:43:23 Done.
1149 profile_->GetOffTheRecordProfile(), 1515 content_source(&notification_source);
1150 event_name, 1516 content::NotificationService::current()->Notify(
1151 json_args, 1517 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
1152 scoped_ptr<base::ListValue>(args->DeepCopy())); 1518 content_source,
1153 } 1519 content::Details<std::string>(&json_args));
1154 DispatchEventInternal(profile_, event_name, json_args, args.Pass());
1155 } 1520 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698