OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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(¬ification_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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 ¬ification_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 } |
OLD | NEW |