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

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

Powered by Google App Engine
This is Rietveld 408576698