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

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

Powered by Google App Engine
This is Rietveld 408576698