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" |
26 #include "base/values.h" | 27 #include "base/values.h" |
27 #include "chrome/browser/browser_process.h" | 28 #include "chrome/browser/browser_process.h" |
28 #include "chrome/browser/download/download_file_icon_extractor.h" | 29 #include "chrome/browser/download/download_file_icon_extractor.h" |
29 #include "chrome/browser/download/download_query.h" | 30 #include "chrome/browser/download/download_query.h" |
30 #include "chrome/browser/download/download_service.h" | 31 #include "chrome/browser/download/download_service.h" |
31 #include "chrome/browser/download/download_service_factory.h" | 32 #include "chrome/browser/download/download_service_factory.h" |
32 #include "chrome/browser/download/download_util.h" | 33 #include "chrome/browser/download/download_util.h" |
33 #include "chrome/browser/extensions/event_names.h" | 34 #include "chrome/browser/extensions/event_names.h" |
34 #include "chrome/browser/extensions/event_router.h" | 35 #include "chrome/browser/extensions/event_router.h" |
35 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 36 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
37 #include "chrome/browser/extensions/extension_info_map.h" | |
36 #include "chrome/browser/extensions/extension_system.h" | 38 #include "chrome/browser/extensions/extension_system.h" |
37 #include "chrome/browser/icon_loader.h" | 39 #include "chrome/browser/icon_loader.h" |
38 #include "chrome/browser/icon_manager.h" | 40 #include "chrome/browser/icon_manager.h" |
39 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 41 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
40 #include "chrome/browser/ui/browser.h" | 42 #include "chrome/browser/ui/browser.h" |
41 #include "chrome/browser/ui/webui/web_ui_util.h" | 43 #include "chrome/browser/ui/webui/web_ui_util.h" |
42 #include "chrome/common/cancelable_task_tracker.h" | 44 #include "chrome/common/cancelable_task_tracker.h" |
43 #include "chrome/common/chrome_notification_types.h" | 45 #include "chrome/common/chrome_notification_types.h" |
44 #include "chrome/common/extensions/api/downloads.h" | 46 #include "chrome/common/extensions/api/downloads.h" |
45 #include "content/public/browser/download_interrupt_reasons.h" | 47 #include "content/public/browser/download_interrupt_reasons.h" |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 } | 174 } |
173 | 175 |
174 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { | 176 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { |
175 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { | 177 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { |
176 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) | 178 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) |
177 return static_cast<DownloadItem::DownloadState>(i); | 179 return static_cast<DownloadItem::DownloadState>(i); |
178 } | 180 } |
179 return DownloadItem::MAX_DOWNLOAD_STATE; | 181 return DownloadItem::MAX_DOWNLOAD_STATE; |
180 } | 182 } |
181 | 183 |
182 bool ValidateFilename(const string16& filename) { | 184 bool ValidateFilename(const FilePath& filename) { |
183 // TODO(benjhayden): More robust validation of filename. | 185 return !filename.empty() && |
184 if ((filename.find('/') != string16::npos) || | 186 (filename.BaseName().value() != FilePath::kCurrentDirectory) && |
185 (filename.find('\\') != string16::npos)) | 187 !filename.ReferencesParent() && |
186 return false; | 188 !filename.IsAbsolute(); |
187 if (filename.size() >= 2u && filename[0] == L'.' && filename[1] == L'.') | |
188 return false; | |
189 return true; | |
190 } | 189 } |
191 | 190 |
192 std::string TimeToISO8601(const base::Time& t) { | 191 std::string TimeToISO8601(const base::Time& t) { |
193 base::Time::Exploded exploded; | 192 base::Time::Exploded exploded; |
194 t.UTCExplode(&exploded); | 193 t.UTCExplode(&exploded); |
195 return base::StringPrintf( | 194 return base::StringPrintf( |
196 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month, | 195 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month, |
197 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second, | 196 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second, |
198 exploded.millisecond); | 197 exploded.millisecond); |
199 } | 198 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 }; | 250 }; |
252 | 251 |
253 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( | 252 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( |
254 const FilePath& path, | 253 const FilePath& path, |
255 IconLoader::IconSize icon_size, | 254 IconLoader::IconSize icon_size, |
256 IconURLCallback callback) { | 255 IconURLCallback callback) { |
257 callback_ = callback; | 256 callback_ = callback; |
258 IconManager* im = g_browser_process->icon_manager(); | 257 IconManager* im = g_browser_process->icon_manager(); |
259 // The contents of the file at |path| may have changed since a previous | 258 // The contents of the file at |path| may have changed since a previous |
260 // request, in which case the associated icon may also have changed. | 259 // request, in which case the associated icon may also have changed. |
261 // Therefore, for the moment we always call LoadIcon instead of attempting | 260 // Therefore, always call LoadIcon instead of attempting a LookupIcon. |
262 // a LookupIcon. | |
263 im->LoadIcon(path, | 261 im->LoadIcon(path, |
264 icon_size, | 262 icon_size, |
265 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, | 263 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, |
266 base::Unretained(this)), | 264 base::Unretained(this)), |
267 &cancelable_task_tracker_); | 265 &cancelable_task_tracker_); |
268 return true; | 266 return true; |
269 } | 267 } |
270 | 268 |
271 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { | 269 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { |
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
398 // TODO(benjhayden): Consider switching from LazyInstance to explicit string | 396 // TODO(benjhayden): Consider switching from LazyInstance to explicit string |
399 // comparisons. | 397 // comparisons. |
400 static base::LazyInstance<SortTypeMap> sorter_types = | 398 static base::LazyInstance<SortTypeMap> sorter_types = |
401 LAZY_INSTANCE_INITIALIZER; | 399 LAZY_INSTANCE_INITIALIZER; |
402 if (sorter_types.Get().size() == 0) | 400 if (sorter_types.Get().size() == 0) |
403 InitSortTypeMap(sorter_types.Get()); | 401 InitSortTypeMap(sorter_types.Get()); |
404 | 402 |
405 std::vector<std::string> order_by_strs; | 403 std::vector<std::string> order_by_strs; |
406 base::SplitString(order_by_str, ' ', &order_by_strs); | 404 base::SplitString(order_by_str, ' ', &order_by_strs); |
407 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); | 405 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); |
408 iter != order_by_strs.end(); ++iter) { | 406 iter != order_by_strs.end(); ++iter) { |
409 std::string term_str = *iter; | 407 std::string term_str = *iter; |
410 if (term_str.empty()) | 408 if (term_str.empty()) |
411 continue; | 409 continue; |
412 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; | 410 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; |
413 if (term_str[0] == '-') { | 411 if (term_str[0] == '-') { |
414 direction = DownloadQuery::DESCENDING; | 412 direction = DownloadQuery::DESCENDING; |
415 term_str = term_str.substr(1); | 413 term_str = term_str.substr(1); |
416 } | 414 } |
417 SortTypeMap::const_iterator sorter_type = | 415 SortTypeMap::const_iterator sorter_type = |
418 sorter_types.Get().find(term_str); | 416 sorter_types.Get().find(term_str); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); | 531 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); |
534 return (data == NULL) ? NULL : | 532 return (data == NULL) ? NULL : |
535 static_cast<ExtensionDownloadsEventRouterData*>(data); | 533 static_cast<ExtensionDownloadsEventRouterData*>(data); |
536 } | 534 } |
537 | 535 |
538 explicit ExtensionDownloadsEventRouterData( | 536 explicit ExtensionDownloadsEventRouterData( |
539 DownloadItem* download_item, | 537 DownloadItem* download_item, |
540 scoped_ptr<base::DictionaryValue> json_item) | 538 scoped_ptr<base::DictionaryValue> json_item) |
541 : updated_(0), | 539 : updated_(0), |
542 changed_fired_(0), | 540 changed_fired_(0), |
543 json_(json_item.Pass()) { | 541 json_(json_item.Pass()), |
542 determiner_index_(-1), | |
543 determined_overwrite_(false) { | |
544 download_item->SetUserData(kKey, this); | 544 download_item->SetUserData(kKey, this); |
545 } | 545 } |
546 | 546 |
547 virtual ~ExtensionDownloadsEventRouterData() { | 547 virtual ~ExtensionDownloadsEventRouterData() { |
548 if (updated_ > 0) { | 548 if (updated_ > 0) { |
549 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", | 549 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", |
550 (changed_fired_ * 100 / updated_)); | 550 (changed_fired_ * 100 / updated_)); |
551 } | 551 } |
552 } | 552 } |
553 | 553 |
554 const base::DictionaryValue& json() const { return *json_.get(); } | 554 const base::DictionaryValue& json() const { return *json_.get(); } |
555 void set_json(scoped_ptr<base::DictionaryValue> json_item) { | 555 void set_json(scoped_ptr<base::DictionaryValue> json_item) { |
556 json_ = json_item.Pass(); | 556 json_ = json_item.Pass(); |
557 } | 557 } |
558 | 558 |
559 void OnItemUpdated() { ++updated_; } | 559 void OnItemUpdated() { ++updated_; } |
560 void OnChangedFired() { ++changed_fired_; } | 560 void OnChangedFired() { ++changed_fired_; } |
561 | 561 |
562 void set_filename_change_callbacks( | |
563 const base::Closure& no_change, | |
564 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { | |
565 filename_no_change_ = no_change; | |
566 filename_change_ = change; | |
567 } | |
568 | |
569 void ClearPendingDeterminers() { | |
570 determiners_.clear(); | |
571 } | |
572 | |
573 void ExtensionUnloaded(const std::string& extension_id) { | |
574 if (determiners_.empty()) | |
Randy Smith (Not in Mondays)
2013/01/17 19:15:42
When I first read through this, I spent a couple o
benjhayden
2013/01/18 20:59:50
Done.
| |
575 return; | |
576 // Remove this extension from |determiners_|. | |
577 for (DeterminerInfoVector::iterator iter = determiners_.begin(); | |
578 iter != determiners_.end();) { | |
579 if (iter->extension_id == extension_id) { | |
580 iter = determiners_.erase(iter); | |
581 } else { | |
582 ++iter; | |
583 } | |
584 } | |
585 CheckAllDeterminersCalled(); | |
586 } | |
587 | |
588 void AddPendingDeterminer(const std::string& extension_id, | |
589 const std::string& sub_event_id, | |
590 const base::Time& installed) { | |
591 determiners_.push_back(DeterminerInfo( | |
592 extension_id, sub_event_id, installed)); | |
593 } | |
594 | |
595 bool DeterminerCallback( | |
596 const std::string& extension_id, | |
597 const std::string& sub_event_id, | |
598 const FilePath& filename, | |
599 bool overwrite) { | |
600 bool filename_valid = ValidateFilename(filename); | |
601 bool found_info = false; | |
602 for (int index = 0; index < static_cast<int>(determiners_.size()); | |
603 ++index) { | |
604 if ((determiners_[index].extension_id == extension_id) && | |
605 (determiners_[index].sub_event_id == sub_event_id)) { | |
606 found_info = true; | |
607 DCHECK(!determiners_[index].reported); | |
608 determiners_[index].reported = true; | |
609 DCHECK_NE(index, determiner_index_); | |
610 // Do not use filename if another determiner has already overridden the | |
611 // filename and they take precedence. Extensions that were installed | |
612 // later take precedence over previous extensions, and listeners that | |
613 // were added later take precedence over previous listeners. | |
614 if (filename_valid && | |
615 ((determiner_index_ < 0) || | |
616 ((determiners_[index].extension_id == | |
617 determiners_[determiner_index_].extension_id) ? | |
618 (determiners_[index].sub_event_id > | |
619 determiners_[determiner_index_].sub_event_id) : | |
620 (determiners_[index].install_time > | |
621 determiners_[determiner_index_].install_time)))) { | |
622 determined_filename_ = filename; | |
623 determined_overwrite_ = overwrite; | |
624 determiner_index_ = index; | |
625 } | |
626 } | |
627 } | |
628 if (!found_info) | |
629 return false; | |
630 CheckAllDeterminersCalled(); | |
631 return filename.empty() || filename_valid; | |
632 } | |
633 | |
562 private: | 634 private: |
635 struct DeterminerInfo { | |
636 DeterminerInfo(const std::string& e_id, | |
637 const std::string& sub_id, | |
638 const base::Time& installed); | |
639 ~DeterminerInfo(); | |
640 | |
641 std::string extension_id; | |
642 std::string sub_event_id; | |
643 base::Time install_time; | |
644 bool reported; | |
645 }; | |
646 typedef std::vector<DeterminerInfo> DeterminerInfoVector; | |
647 | |
563 static const char kKey[]; | 648 static const char kKey[]; |
564 | 649 |
650 void CheckAllDeterminersCalled() { | |
651 for (DeterminerInfoVector::iterator iter = determiners_.begin(); | |
652 iter != determiners_.end(); ++iter) { | |
653 if (!iter->reported) | |
654 return; | |
655 } | |
656 ClearPendingDeterminers(); | |
657 if (determined_filename_.empty()) { | |
658 filename_no_change_.Run(); | |
659 } else { | |
660 filename_change_.Run(determined_filename_, determined_overwrite_); | |
661 } | |
662 } | |
663 | |
565 int updated_; | 664 int updated_; |
566 int changed_fired_; | 665 int changed_fired_; |
567 scoped_ptr<base::DictionaryValue> json_; | 666 scoped_ptr<base::DictionaryValue> json_; |
568 | 667 |
668 base::Closure filename_no_change_; | |
669 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_; | |
670 | |
671 DeterminerInfoVector determiners_; | |
672 | |
673 int determiner_index_; | |
674 FilePath determined_filename_; | |
Randy Smith (Not in Mondays)
2013/01/17 19:15:42
I may have missed it, but where do you reset these
benjhayden
2013/01/18 20:59:50
Good catch. Added that to right after where filena
| |
675 bool determined_overwrite_; | |
676 | |
569 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); | 677 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); |
570 }; | 678 }; |
571 | 679 |
680 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo( | |
681 const std::string& e_id, | |
682 const std::string& sub_id, | |
683 const base::Time& installed) | |
684 : extension_id(e_id), | |
685 sub_event_id(sub_id), | |
686 install_time(installed), | |
687 reported(false) { | |
688 } | |
689 | |
690 ExtensionDownloadsEventRouterData::DeterminerInfo::~DeterminerInfo() {} | |
691 | |
572 const char ExtensionDownloadsEventRouterData::kKey[] = | 692 const char ExtensionDownloadsEventRouterData::kKey[] = |
573 "DownloadItem ExtensionDownloadsEventRouterData"; | 693 "DownloadItem ExtensionDownloadsEventRouterData"; |
574 | 694 |
575 class ManagerDestructionObserver : public DownloadManager::Observer { | 695 class ManagerDestructionObserver : public DownloadManager::Observer { |
576 public: | 696 public: |
577 static void CheckForHistoryFilesRemoval(DownloadManager* manager) { | 697 static void CheckForHistoryFilesRemoval(DownloadManager* manager) { |
578 if (!manager) | 698 if (!manager) |
579 return; | 699 return; |
580 if (!manager_file_existence_last_checked_) | 700 if (!manager_file_existence_last_checked_) |
581 manager_file_existence_last_checked_ = | 701 manager_file_existence_last_checked_ = |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 | 744 |
625 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver); | 745 DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver); |
626 }; | 746 }; |
627 | 747 |
628 std::map<DownloadManager*, ManagerDestructionObserver*>* | 748 std::map<DownloadManager*, ManagerDestructionObserver*>* |
629 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL; | 749 ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL; |
630 | 750 |
631 } // namespace | 751 } // namespace |
632 | 752 |
633 DownloadsDownloadFunction::DownloadsDownloadFunction() {} | 753 DownloadsDownloadFunction::DownloadsDownloadFunction() {} |
754 | |
634 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} | 755 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} |
635 | 756 |
636 bool DownloadsDownloadFunction::RunImpl() { | 757 bool DownloadsDownloadFunction::RunImpl() { |
637 scoped_ptr<extensions::api::downloads::Download::Params> params( | 758 scoped_ptr<extensions::api::downloads::Download::Params> params( |
638 extensions::api::downloads::Download::Params::Create(*args_)); | 759 extensions::api::downloads::Download::Params::Create(*args_)); |
639 EXTENSION_FUNCTION_VALIDATE(params.get()); | 760 EXTENSION_FUNCTION_VALIDATE(params.get()); |
640 const extensions::api::downloads::DownloadOptions& options = params->options; | 761 const extensions::api::downloads::DownloadOptions& options = params->options; |
641 GURL download_url(options.url); | 762 GURL download_url(options.url); |
642 if (!download_url.is_valid() || | 763 if (!download_url.is_valid() || |
643 (!download_url.SchemeIs("data") && | 764 (!download_url.SchemeIs("data") && |
(...skipping 16 matching lines...) Expand all Loading... | |
660 | 781 |
661 if (options.filename.get()) { | 782 if (options.filename.get()) { |
662 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of | 783 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of |
663 // std::strings. Can't get filename16 from options.ToValue() because that | 784 // std::strings. Can't get filename16 from options.ToValue() because that |
664 // converts it from std::string. | 785 // converts it from std::string. |
665 base::DictionaryValue* options_value = NULL; | 786 base::DictionaryValue* options_value = NULL; |
666 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); | 787 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); |
667 string16 filename16; | 788 string16 filename16; |
668 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( | 789 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( |
669 kFilenameKey, &filename16)); | 790 kFilenameKey, &filename16)); |
670 if (!ValidateFilename(filename16)) { | 791 #if defined(OS_WIN) |
792 FilePath file_path(filename16); | |
Randy Smith (Not in Mondays)
2013/01/17 19:15:42
nit: Move everything that's only relevant to creat
benjhayden
2013/01/18 20:59:50
No, filename16 is used on L803 of this PS.
| |
793 #elif defined(OS_POSIX) | |
794 FilePath file_path(*options.filename.get()); | |
795 #endif | |
796 if (!ValidateFilename(file_path) || | |
797 (file_path.DirName().value() != FilePath::kCurrentDirectory)) { | |
671 error_ = download_extension_errors::kGenericError; | 798 error_ = download_extension_errors::kGenericError; |
672 return false; | 799 return false; |
673 } | 800 } |
674 // TODO(benjhayden) Ensure that this filename is interpreted as a path | 801 // TODO(benjhayden) Ensure that this filename is interpreted as a path |
675 // relative to the default downloads directory without allowing '..'. | 802 // relative to the default downloads directory without allowing '..'. |
676 download_params->set_suggested_name(filename16); | 803 download_params->set_suggested_name(filename16); |
677 } | 804 } |
678 | 805 |
679 if (options.save_as.get()) | 806 if (options.save_as.get()) |
680 download_params->set_prompt(*options.save_as.get()); | 807 download_params->set_prompt(*options.save_as.get()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
720 DCHECK_EQ(net::OK, error); | 847 DCHECK_EQ(net::OK, error); |
721 SetResult(base::Value::CreateIntegerValue(item->GetId())); | 848 SetResult(base::Value::CreateIntegerValue(item->GetId())); |
722 } else { | 849 } else { |
723 DCHECK_NE(net::OK, error); | 850 DCHECK_NE(net::OK, error); |
724 error_ = net::ErrorToString(error); | 851 error_ = net::ErrorToString(error); |
725 } | 852 } |
726 SendResponse(error_.empty()); | 853 SendResponse(error_.empty()); |
727 } | 854 } |
728 | 855 |
729 DownloadsSearchFunction::DownloadsSearchFunction() {} | 856 DownloadsSearchFunction::DownloadsSearchFunction() {} |
857 | |
730 DownloadsSearchFunction::~DownloadsSearchFunction() {} | 858 DownloadsSearchFunction::~DownloadsSearchFunction() {} |
731 | 859 |
732 bool DownloadsSearchFunction::RunImpl() { | 860 bool DownloadsSearchFunction::RunImpl() { |
733 scoped_ptr<extensions::api::downloads::Search::Params> params( | 861 scoped_ptr<extensions::api::downloads::Search::Params> params( |
734 extensions::api::downloads::Search::Params::Create(*args_)); | 862 extensions::api::downloads::Search::Params::Create(*args_)); |
735 EXTENSION_FUNCTION_VALIDATE(params.get()); | 863 EXTENSION_FUNCTION_VALIDATE(params.get()); |
736 DownloadManager* manager = NULL; | 864 DownloadManager* manager = NULL; |
737 DownloadManager* incognito_manager = NULL; | 865 DownloadManager* incognito_manager = NULL; |
738 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); | 866 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); |
739 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager); | 867 ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager); |
(...skipping 17 matching lines...) Expand all Loading... | |
757 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( | 885 scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( |
758 *it, off_record)); | 886 *it, off_record)); |
759 json_results->Append(json_item.release()); | 887 json_results->Append(json_item.release()); |
760 } | 888 } |
761 SetResult(json_results); | 889 SetResult(json_results); |
762 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); | 890 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); |
763 return true; | 891 return true; |
764 } | 892 } |
765 | 893 |
766 DownloadsPauseFunction::DownloadsPauseFunction() {} | 894 DownloadsPauseFunction::DownloadsPauseFunction() {} |
895 | |
767 DownloadsPauseFunction::~DownloadsPauseFunction() {} | 896 DownloadsPauseFunction::~DownloadsPauseFunction() {} |
768 | 897 |
769 bool DownloadsPauseFunction::RunImpl() { | 898 bool DownloadsPauseFunction::RunImpl() { |
770 scoped_ptr<extensions::api::downloads::Pause::Params> params( | 899 scoped_ptr<extensions::api::downloads::Pause::Params> params( |
771 extensions::api::downloads::Pause::Params::Create(*args_)); | 900 extensions::api::downloads::Pause::Params::Create(*args_)); |
772 EXTENSION_FUNCTION_VALIDATE(params.get()); | 901 EXTENSION_FUNCTION_VALIDATE(params.get()); |
773 DownloadItem* download_item = GetDownloadIfInProgress( | 902 DownloadItem* download_item = GetDownloadIfInProgress( |
774 profile(), include_incognito(), params->download_id); | 903 profile(), include_incognito(), params->download_id); |
775 if (download_item == NULL) { | 904 if (download_item == NULL) { |
776 // This could be due to an invalid download ID, or it could be due to the | 905 // This could be due to an invalid download ID, or it could be due to the |
777 // download not being currently active. | 906 // download not being currently active. |
778 error_ = download_extension_errors::kInvalidOperationError; | 907 error_ = download_extension_errors::kInvalidOperationError; |
779 } else { | 908 } else { |
780 // If the item is already paused, this is a no-op and the | 909 // If the item is already paused, this is a no-op and the |
781 // operation will silently succeed. | 910 // operation will silently succeed. |
782 download_item->Pause(); | 911 download_item->Pause(); |
783 } | 912 } |
784 if (error_.empty()) | 913 if (error_.empty()) |
785 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE); | 914 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE); |
786 return error_.empty(); | 915 return error_.empty(); |
787 } | 916 } |
788 | 917 |
789 DownloadsResumeFunction::DownloadsResumeFunction() {} | 918 DownloadsResumeFunction::DownloadsResumeFunction() {} |
919 | |
790 DownloadsResumeFunction::~DownloadsResumeFunction() {} | 920 DownloadsResumeFunction::~DownloadsResumeFunction() {} |
791 | 921 |
792 bool DownloadsResumeFunction::RunImpl() { | 922 bool DownloadsResumeFunction::RunImpl() { |
793 scoped_ptr<extensions::api::downloads::Resume::Params> params( | 923 scoped_ptr<extensions::api::downloads::Resume::Params> params( |
794 extensions::api::downloads::Resume::Params::Create(*args_)); | 924 extensions::api::downloads::Resume::Params::Create(*args_)); |
795 EXTENSION_FUNCTION_VALIDATE(params.get()); | 925 EXTENSION_FUNCTION_VALIDATE(params.get()); |
796 DownloadItem* download_item = GetDownloadIfInProgress( | 926 DownloadItem* download_item = GetDownloadIfInProgress( |
797 profile(), include_incognito(), params->download_id); | 927 profile(), include_incognito(), params->download_id); |
798 if (download_item == NULL) { | 928 if (download_item == NULL) { |
799 // This could be due to an invalid download ID, or it could be due to the | 929 // This could be due to an invalid download ID, or it could be due to the |
800 // download not being currently active. | 930 // download not being currently active. |
801 error_ = download_extension_errors::kInvalidOperationError; | 931 error_ = download_extension_errors::kInvalidOperationError; |
802 } else { | 932 } else { |
803 // Note that if the item isn't paused, this will be a no-op, and | 933 // Note that if the item isn't paused, this will be a no-op, and |
804 // we will silently treat the extension call as a success. | 934 // the extension call will seem successful. |
805 download_item->Resume(); | 935 download_item->Resume(); |
806 } | 936 } |
807 if (error_.empty()) | 937 if (error_.empty()) |
808 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); | 938 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); |
809 return error_.empty(); | 939 return error_.empty(); |
810 } | 940 } |
811 | 941 |
812 DownloadsCancelFunction::DownloadsCancelFunction() {} | 942 DownloadsCancelFunction::DownloadsCancelFunction() {} |
943 | |
813 DownloadsCancelFunction::~DownloadsCancelFunction() {} | 944 DownloadsCancelFunction::~DownloadsCancelFunction() {} |
814 | 945 |
815 bool DownloadsCancelFunction::RunImpl() { | 946 bool DownloadsCancelFunction::RunImpl() { |
816 scoped_ptr<extensions::api::downloads::Resume::Params> params( | 947 scoped_ptr<extensions::api::downloads::Resume::Params> params( |
817 extensions::api::downloads::Resume::Params::Create(*args_)); | 948 extensions::api::downloads::Resume::Params::Create(*args_)); |
818 EXTENSION_FUNCTION_VALIDATE(params.get()); | 949 EXTENSION_FUNCTION_VALIDATE(params.get()); |
819 DownloadItem* download_item = GetDownloadIfInProgress( | 950 DownloadItem* download_item = GetDownloadIfInProgress( |
820 profile(), include_incognito(), params->download_id); | 951 profile(), include_incognito(), params->download_id); |
821 if (download_item != NULL) | 952 if (download_item != NULL) |
822 download_item->Cancel(true); | 953 download_item->Cancel(true); |
823 // |download_item| can be NULL if the download ID was invalid or if the | 954 // |download_item| can be NULL if the download ID was invalid or if the |
824 // download is not currently active. Either way, we don't consider it a | 955 // download is not currently active. Either way, it's not a failure. |
825 // failure. | |
826 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); | 956 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); |
827 return true; | 957 return true; |
828 } | 958 } |
829 | 959 |
830 DownloadsEraseFunction::DownloadsEraseFunction() {} | 960 DownloadsEraseFunction::DownloadsEraseFunction() {} |
961 | |
831 DownloadsEraseFunction::~DownloadsEraseFunction() {} | 962 DownloadsEraseFunction::~DownloadsEraseFunction() {} |
832 | 963 |
833 bool DownloadsEraseFunction::RunImpl() { | 964 bool DownloadsEraseFunction::RunImpl() { |
834 scoped_ptr<extensions::api::downloads::Erase::Params> params( | 965 scoped_ptr<extensions::api::downloads::Erase::Params> params( |
835 extensions::api::downloads::Erase::Params::Create(*args_)); | 966 extensions::api::downloads::Erase::Params::Create(*args_)); |
836 EXTENSION_FUNCTION_VALIDATE(params.get()); | 967 EXTENSION_FUNCTION_VALIDATE(params.get()); |
837 DownloadManager* manager = NULL; | 968 DownloadManager* manager = NULL; |
838 DownloadManager* incognito_manager = NULL; | 969 DownloadManager* incognito_manager = NULL; |
839 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); | 970 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); |
840 DownloadQuery::DownloadVector results; | 971 DownloadQuery::DownloadVector results; |
841 RunDownloadQuery(params->query, | 972 RunDownloadQuery(params->query, |
842 manager, | 973 manager, |
843 incognito_manager, | 974 incognito_manager, |
844 &error_, | 975 &error_, |
845 &results); | 976 &results); |
846 if (!error_.empty()) | 977 if (!error_.empty()) |
847 return false; | 978 return false; |
848 base::ListValue* json_results = new base::ListValue(); | 979 base::ListValue* json_results = new base::ListValue(); |
849 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); | 980 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); |
850 it != results.end(); ++it) { | 981 it != results.end(); ++it) { |
851 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); | 982 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); |
852 (*it)->Remove(); | 983 (*it)->Remove(); |
853 } | 984 } |
854 SetResult(json_results); | 985 SetResult(json_results); |
855 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); | 986 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); |
856 return true; | 987 return true; |
857 } | 988 } |
858 | 989 |
859 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() {} | 990 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} |
860 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} | |
861 | 991 |
862 bool DownloadsSetDestinationFunction::RunImpl() { | |
863 scoped_ptr<extensions::api::downloads::SetDestination::Params> params( | |
864 extensions::api::downloads::SetDestination::Params::Create(*args_)); | |
865 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
866 error_ = download_extension_errors::kNotImplementedError; | |
867 if (error_.empty()) | |
868 RecordApiFunctions(DOWNLOADS_FUNCTION_SET_DESTINATION); | |
869 return error_.empty(); | |
870 } | |
871 | |
872 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} | |
873 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} | 992 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} |
874 | 993 |
875 bool DownloadsAcceptDangerFunction::RunImpl() { | 994 bool DownloadsAcceptDangerFunction::RunImpl() { |
876 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( | 995 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( |
877 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); | 996 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); |
878 EXTENSION_FUNCTION_VALIDATE(params.get()); | 997 EXTENSION_FUNCTION_VALIDATE(params.get()); |
879 error_ = download_extension_errors::kNotImplementedError; | 998 error_ = download_extension_errors::kNotImplementedError; |
880 if (error_.empty()) | 999 if (error_.empty()) |
881 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER); | 1000 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER); |
882 return error_.empty(); | 1001 return error_.empty(); |
883 } | 1002 } |
884 | 1003 |
885 DownloadsShowFunction::DownloadsShowFunction() {} | 1004 DownloadsShowFunction::DownloadsShowFunction() {} |
1005 | |
886 DownloadsShowFunction::~DownloadsShowFunction() {} | 1006 DownloadsShowFunction::~DownloadsShowFunction() {} |
887 | 1007 |
888 bool DownloadsShowFunction::RunImpl() { | 1008 bool DownloadsShowFunction::RunImpl() { |
889 scoped_ptr<extensions::api::downloads::Show::Params> params( | 1009 scoped_ptr<extensions::api::downloads::Show::Params> params( |
890 extensions::api::downloads::Show::Params::Create(*args_)); | 1010 extensions::api::downloads::Show::Params::Create(*args_)); |
891 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1011 EXTENSION_FUNCTION_VALIDATE(params.get()); |
892 DownloadItem* download_item = GetDownload( | 1012 DownloadItem* download_item = GetDownload( |
893 profile(), include_incognito(), params->download_id); | 1013 profile(), include_incognito(), params->download_id); |
894 if (!download_item) { | 1014 if (!download_item) { |
895 error_ = download_extension_errors::kInvalidOperationError; | 1015 error_ = download_extension_errors::kInvalidOperationError; |
896 return false; | 1016 return false; |
897 } | 1017 } |
898 download_item->ShowDownloadInShell(); | 1018 download_item->ShowDownloadInShell(); |
899 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); | 1019 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); |
900 return true; | 1020 return true; |
901 } | 1021 } |
902 | 1022 |
903 DownloadsOpenFunction::DownloadsOpenFunction() {} | 1023 DownloadsOpenFunction::DownloadsOpenFunction() {} |
1024 | |
904 DownloadsOpenFunction::~DownloadsOpenFunction() {} | 1025 DownloadsOpenFunction::~DownloadsOpenFunction() {} |
905 | 1026 |
906 bool DownloadsOpenFunction::RunImpl() { | 1027 bool DownloadsOpenFunction::RunImpl() { |
907 scoped_ptr<extensions::api::downloads::Open::Params> params( | 1028 scoped_ptr<extensions::api::downloads::Open::Params> params( |
908 extensions::api::downloads::Open::Params::Create(*args_)); | 1029 extensions::api::downloads::Open::Params::Create(*args_)); |
909 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1030 EXTENSION_FUNCTION_VALIDATE(params.get()); |
910 DownloadItem* download_item = GetDownload( | 1031 DownloadItem* download_item = GetDownload( |
911 profile(), include_incognito(), params->download_id); | 1032 profile(), include_incognito(), params->download_id); |
912 if (!download_item || !download_item->IsComplete()) { | 1033 if (!download_item || !download_item->IsComplete()) { |
913 error_ = download_extension_errors::kInvalidOperationError; | 1034 error_ = download_extension_errors::kInvalidOperationError; |
914 return false; | 1035 return false; |
915 } | 1036 } |
916 download_item->OpenDownload(); | 1037 download_item->OpenDownload(); |
917 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); | 1038 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); |
918 return true; | 1039 return true; |
919 } | 1040 } |
920 | 1041 |
921 DownloadsDragFunction::DownloadsDragFunction() {} | 1042 DownloadsDragFunction::DownloadsDragFunction() {} |
1043 | |
922 DownloadsDragFunction::~DownloadsDragFunction() {} | 1044 DownloadsDragFunction::~DownloadsDragFunction() {} |
923 | 1045 |
924 bool DownloadsDragFunction::RunImpl() { | 1046 bool DownloadsDragFunction::RunImpl() { |
925 scoped_ptr<extensions::api::downloads::Drag::Params> params( | 1047 scoped_ptr<extensions::api::downloads::Drag::Params> params( |
926 extensions::api::downloads::Drag::Params::Create(*args_)); | 1048 extensions::api::downloads::Drag::Params::Create(*args_)); |
927 EXTENSION_FUNCTION_VALIDATE(params.get()); | 1049 EXTENSION_FUNCTION_VALIDATE(params.get()); |
928 DownloadItem* download_item = GetDownload( | 1050 DownloadItem* download_item = GetDownload( |
929 profile(), include_incognito(), params->download_id); | 1051 profile(), include_incognito(), params->download_id); |
930 content::WebContents* web_contents = | 1052 content::WebContents* web_contents = |
931 dispatcher()->delegate()->GetAssociatedWebContents(); | 1053 dispatcher()->delegate()->GetAssociatedWebContents(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
966 int icon_size = kDefaultIconSize; | 1088 int icon_size = kDefaultIconSize; |
967 if (options && options->size.get()) | 1089 if (options && options->size.get()) |
968 icon_size = *options->size.get(); | 1090 icon_size = *options->size.get(); |
969 DownloadItem* download_item = GetDownload( | 1091 DownloadItem* download_item = GetDownload( |
970 profile(), include_incognito(), params->download_id); | 1092 profile(), include_incognito(), params->download_id); |
971 if (!download_item || download_item->GetTargetFilePath().empty()) { | 1093 if (!download_item || download_item->GetTargetFilePath().empty()) { |
972 error_ = download_extension_errors::kInvalidOperationError; | 1094 error_ = download_extension_errors::kInvalidOperationError; |
973 return false; | 1095 return false; |
974 } | 1096 } |
975 // In-progress downloads return the intermediate filename for GetFullPath() | 1097 // In-progress downloads return the intermediate filename for GetFullPath() |
976 // which doesn't have the final extension. Therefore we won't be able to | 1098 // which doesn't have the final extension. Therefore a good file icon can't be |
977 // derive a good file icon for it. So we use GetTargetFilePath() instead. | 1099 // found, so use GetTargetFilePath() instead. |
978 DCHECK(icon_extractor_.get()); | 1100 DCHECK(icon_extractor_.get()); |
979 DCHECK(icon_size == 16 || icon_size == 32); | 1101 DCHECK(icon_size == 16 || icon_size == 32); |
980 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( | 1102 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( |
981 download_item->GetTargetFilePath(), | 1103 download_item->GetTargetFilePath(), |
982 IconLoaderSizeFromPixelSize(icon_size), | 1104 IconLoaderSizeFromPixelSize(icon_size), |
983 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); | 1105 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); |
984 return true; | 1106 return true; |
985 } | 1107 } |
986 | 1108 |
987 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { | 1109 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { |
988 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
989 if (url.empty()) { | 1111 if (url.empty()) { |
990 error_ = download_extension_errors::kIconNotFoundError; | 1112 error_ = download_extension_errors::kIconNotFoundError; |
991 } else { | 1113 } else { |
992 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); | 1114 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); |
993 SetResult(base::Value::CreateStringValue(url)); | 1115 SetResult(base::Value::CreateStringValue(url)); |
994 } | 1116 } |
995 SendResponse(error_.empty()); | 1117 SendResponse(error_.empty()); |
996 } | 1118 } |
997 | 1119 |
1120 // The method by which extensions hook into the filename determination process | |
1121 // is based on the method by which the webRequest API allows extensions to hook | |
1122 // into the resource loading process. Extensions that wish to play a part in | |
1123 // the filename determination process call | |
1124 // chrome.downloads.onDeterminingFilename.addListener, which secretly (see | |
1125 // chrome/renderer/resources/extensions/downloads_custom_bindings.js) calls | |
1126 // DownloadsInternalAddFilenameDeterminerFunction (see ../downloads_internal/), | |
1127 // which adds the extension's ID to the profile's ExtensionDownloadsEventRouter | |
1128 // (EDER). | |
1129 // | |
1130 // When a download's filename is being determined, | |
1131 // ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone (CVRBD) passes | |
1132 // 2 callbacks to EDER::OnDownloadFilenameDetermined (ODFD), which stores the | |
1133 // callbacks in the item's ExtensionDownloadsEventRouterData (EDERD) along with | |
1134 // all of the extension IDs that are listening for onDeterminingFilename events. | |
1135 // ODFD dispatches chrome.downloads.onDeterminingFilename. | |
1136 // | |
1137 // When the extension's event handler returns, downloads_custom_bindings.js | |
1138 // calls DownloadsInternalDetermineFilenameFunction::RunImpl, which notifies the | |
1139 // item's EDERD. | |
1140 // | |
1141 // When the last extension's event handler returns, EDERD calls one of the two | |
1142 // callbacks that CVRBD passed to ODFD, allowing CDMD to complete the filename | |
1143 // determination process. If multiple extensions wish to override the filename, | |
1144 // then the extension that was last installed wins; if multiple determiners | |
1145 // within an extension compete, then the determiner that was last added wins. | |
1146 | |
1147 bool ExtensionDownloadsEventRouter::AddFilenameDeterminer( | |
1148 Profile* profile, | |
1149 const std::string& ext_id, | |
1150 const std::string& sub_event_id) { | |
1151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1152 // Only incognito/regular renderer processes receive onDeterminingFilename | |
1153 // events for incognito/regular downloads. Do not automatically add this | |
Randy Smith (Not in Mondays)
2013/01/17 19:15:42
So this seems weird to me. My understanding (plea
benjhayden
2013/01/18 20:59:50
Nope, when incognito extensions' renderers call on
Randy Smith (Not in Mondays)
2013/01/22 19:43:08
Sounds good. As discussed offline, could you:
* C
| |
1154 // determiner to the other (incognito/regular) EDER; if the extension wants to | |
1155 // listen for onDeterminingFilename in those extension renderer processes, | |
1156 // then it will call addListener there, and |profile| will be | |
1157 // incognito/regular for those addListener calls, so they will use the | |
1158 // incognito/regular EDER. | |
1159 ExtensionDownloadsEventRouter* router = | |
1160 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); | |
1161 if (!router) | |
1162 return false; | |
1163 for (DeterminerVector::const_iterator iter = router->determiners_.begin(); | |
1164 iter != router->determiners_.end(); ++iter) { | |
1165 if (iter->extension_id == ext_id) { | |
1166 DCHECK_NE(iter->sub_event_id, sub_event_id); | |
1167 } | |
1168 if ((iter->extension_id == ext_id) && | |
1169 (iter->sub_event_id == sub_event_id)) | |
1170 return false; | |
1171 } | |
1172 router->determiners_.push_back(DeterminerId(ext_id, sub_event_id)); | |
1173 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( | |
1174 &ExtensionDownloadsEventRouter::GetInstallTime, | |
1175 ext_id, | |
1176 scoped_refptr<ExtensionInfoMap>( | |
1177 extensions::ExtensionSystem::Get(profile)->info_map()), | |
1178 &router->determiners_[router->determiners_.size() - 1].installed)); | |
1179 return true; | |
1180 } | |
1181 | |
1182 void ExtensionDownloadsEventRouter::GetInstallTime( | |
1183 const std::string& ext_id, | |
1184 ExtensionInfoMap* info_map, | |
1185 base::Time* install_time) { | |
1186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
1187 *install_time = info_map->GetInstallTime(ext_id); | |
1188 } | |
1189 | |
1190 ExtensionDownloadsEventRouter::DeterminerId::DeterminerId( | |
Randy Smith (Not in Mondays)
2013/01/17 19:15:42
So there's an officially sanctioned order for meth
benjhayden
2013/01/18 20:59:50
Done.
| |
1191 const std::string& ext_id, | |
1192 const std::string& sub_id) | |
1193 : extension_id(ext_id), | |
1194 sub_event_id(sub_id) { | |
1195 } | |
1196 | |
1197 ExtensionDownloadsEventRouter::DeterminerId::~DeterminerId() {} | |
1198 | |
1199 bool ExtensionDownloadsEventRouter::RemoveFilenameDeterminer( | |
1200 Profile* profile, | |
1201 const std::string& ext_id, | |
1202 const std::string& sub_event_id) { | |
1203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1204 ExtensionDownloadsEventRouter* router = | |
1205 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); | |
1206 for (DeterminerVector::iterator iter = router->determiners_.begin(); | |
1207 iter != router->determiners_.end(); ++iter) { | |
1208 if (iter->extension_id == ext_id && iter->sub_event_id == sub_event_id) { | |
1209 router->determiners_.erase(iter); | |
1210 return true; | |
1211 } | |
1212 } | |
1213 DCHECK(false) << ext_id << " " << sub_event_id; | |
1214 return false; | |
1215 } | |
1216 | |
1217 bool ExtensionDownloadsEventRouter::DetermineFilename( | |
1218 Profile* profile, | |
1219 bool include_incognito, | |
1220 const std::string& ext_id, | |
1221 const std::string& sub_event_id, | |
1222 int download_id, | |
1223 const FilePath& filename, | |
1224 bool overwrite) { | |
1225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1226 DownloadItem* item = GetDownloadIfInProgress( | |
1227 profile, include_incognito, download_id); | |
1228 if (!item) | |
1229 return false; | |
1230 ExtensionDownloadsEventRouterData* data = | |
1231 ExtensionDownloadsEventRouterData::Get(item); | |
1232 if (!data) | |
1233 return false; | |
1234 return data->DeterminerCallback(ext_id, sub_event_id, filename, overwrite); | |
1235 } | |
1236 | |
998 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( | 1237 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
999 Profile* profile, | 1238 Profile* profile, |
1000 DownloadManager* manager) | 1239 DownloadManager* manager) |
1001 : profile_(profile), | 1240 : profile_(profile), |
1002 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { | 1241 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { |
1003 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1004 DCHECK(profile_); | 1243 DCHECK(profile_); |
1244 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
1245 content::Source<Profile>(profile_)); | |
1246 } | |
1247 | |
1248 void ExtensionDownloadsEventRouter::Observe( | |
1249 int type, | |
1250 const content::NotificationSource& source, | |
1251 const content::NotificationDetails& details) { | |
1252 switch (type) { | |
1253 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | |
1254 const extensions::Extension* extension = content::Details< | |
1255 extensions::UnloadedExtensionInfo>(details)->extension; | |
1256 // Remove this extension from |determiners_|. | |
1257 for (DeterminerVector::iterator iter = determiners_.begin(); | |
1258 iter != determiners_.end();) { | |
1259 if (iter->extension_id == extension->id()) { | |
1260 iter = determiners_.erase(iter); | |
1261 } else { | |
1262 ++iter; | |
1263 } | |
1264 } | |
1265 // Notify any items that may be waiting for callbacks from this extension. | |
1266 DownloadManager* manager = notifier_.GetManager(); | |
1267 if (manager) { | |
1268 DownloadManager::DownloadVector items; | |
1269 manager->GetAllDownloads(&items); | |
1270 for (DownloadManager::DownloadVector::const_iterator iter = | |
1271 items.begin(); | |
1272 iter != items.end(); ++iter) { | |
1273 ExtensionDownloadsEventRouterData* data = | |
1274 ExtensionDownloadsEventRouterData::Get(*iter); | |
1275 if (data) | |
1276 data->ExtensionUnloaded(extension->id()); | |
1277 } | |
1278 } | |
1279 break; | |
1280 } | |
1281 default: | |
1282 NOTREACHED(); | |
1283 break; | |
1284 } | |
1005 } | 1285 } |
1006 | 1286 |
1007 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | 1287 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
1008 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1009 } | 1289 } |
1010 | 1290 |
1011 void ExtensionDownloadsEventRouter::OnDownloadCreated( | 1291 void ExtensionDownloadsEventRouter::OnDownloadCreated( |
1012 DownloadManager* manager, DownloadItem* download_item) { | 1292 DownloadManager* manager, DownloadItem* download_item) { |
1013 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1014 if (download_item->IsTemporary()) | 1294 if (download_item->IsTemporary()) |
1015 return; | 1295 return; |
1016 | 1296 |
1017 scoped_ptr<base::DictionaryValue> json_item( | 1297 scoped_ptr<base::DictionaryValue> json_item( |
1018 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); | 1298 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
1019 DispatchEvent(extensions::event_names::kOnDownloadCreated, | 1299 DispatchEvent(extensions::event_names::kOnDownloadCreated, |
1300 true, | |
1020 json_item->DeepCopy()); | 1301 json_item->DeepCopy()); |
1021 if (!ExtensionDownloadsEventRouterData::Get(download_item)) | 1302 if (!ExtensionDownloadsEventRouterData::Get(download_item)) |
1022 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); | 1303 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); |
1023 } | 1304 } |
1024 | 1305 |
1306 void ExtensionDownloadsEventRouter::OnDownloadFilenameDetermined( | |
1307 DownloadItem* item, | |
1308 const FilePath& suggested_path, | |
1309 const base::Closure& no_change, | |
1310 const FilenameChangedCallback& change) { | |
1311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1312 if (determiners_.empty()) { | |
1313 no_change.Run(); | |
1314 return; | |
1315 } | |
1316 | |
1317 ExtensionDownloadsEventRouterData* data = | |
1318 ExtensionDownloadsEventRouterData::Get(item); | |
1319 data->set_filename_change_callbacks(no_change, change); | |
1320 data->ClearPendingDeterminers(); | |
1321 std::set<std::string> sub_events; | |
1322 for (DeterminerVector::const_iterator iter = determiners_.begin(); | |
1323 iter != determiners_.end(); ++iter) { | |
1324 data->AddPendingDeterminer(iter->extension_id, | |
1325 iter->sub_event_id, | |
1326 iter->installed); | |
1327 sub_events.insert(iter->sub_event_id); | |
1328 } | |
1329 std::string event_name( | |
1330 extensions::event_names::kOnDownloadDeterminingFilename); | |
1331 event_name += "/"; | |
1332 for (std::set<std::string>::const_iterator iter = sub_events.begin(); | |
1333 iter != sub_events.end(); ++iter) { | |
1334 base::DictionaryValue* json = DownloadItemToJSON( | |
1335 item, profile_->IsOffTheRecord()).release(); | |
1336 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); | |
1337 // If there's a listener in an incognito extension renderer, then it will | |
1338 // have registered its own determiner in the incognito EDER, which will be | |
1339 // called for incognito downloads. | |
1340 DispatchEvent((event_name + (*iter)).c_str(), false, json); | |
1341 } | |
1342 } | |
1343 | |
1025 void ExtensionDownloadsEventRouter::OnDownloadUpdated( | 1344 void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
1026 DownloadManager* manager, DownloadItem* download_item) { | 1345 DownloadManager* manager, DownloadItem* download_item) { |
1027 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1028 if (download_item->IsTemporary()) | 1347 if (download_item->IsTemporary()) |
1029 return; | 1348 return; |
1030 | 1349 |
1031 ExtensionDownloadsEventRouterData* data = | 1350 ExtensionDownloadsEventRouterData* data = |
1032 ExtensionDownloadsEventRouterData::Get(download_item); | 1351 ExtensionDownloadsEventRouterData::Get(download_item); |
1033 if (!data) { | 1352 if (!data) { |
1034 // The download_item probably transitioned from temporary to not temporary. | 1353 // The download_item probably transitioned from temporary to not temporary. |
1035 OnDownloadCreated(manager, download_item); | 1354 OnDownloadCreated(manager, download_item); |
1036 return; | 1355 return; |
1037 } | 1356 } |
1038 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( | 1357 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( |
1039 download_item, profile_->IsOffTheRecord())); | 1358 download_item, profile_->IsOffTheRecord())); |
1040 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); | 1359 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
1041 delta->SetInteger(kIdKey, download_item->GetId()); | 1360 delta->SetInteger(kIdKey, download_item->GetId()); |
1042 std::set<std::string> new_fields; | 1361 std::set<std::string> new_fields; |
1043 bool changed = false; | 1362 bool changed = false; |
1044 | 1363 |
1045 // For each field in the new json representation of the download_item except | 1364 // For each field in the new json representation of the download_item except |
1046 // the bytesReceived field, if the field has changed from the previous old | 1365 // the bytesReceived field, if the field has changed from the previous old |
1047 // json, set the differences in the |delta| object and remember that something | 1366 // json, set the differences in the |delta| object and remember that something |
1048 // significant changed. | 1367 // significant changed. |
1049 for (base::DictionaryValue::Iterator iter(*new_json.get()); | 1368 for (base::DictionaryValue::Iterator iter(*new_json.get()); |
(...skipping 19 matching lines...) Expand all Loading... | |
1069 if (new_fields.find(iter.key()) == new_fields.end()) { | 1388 if (new_fields.find(iter.key()) == new_fields.end()) { |
1070 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); | 1389 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); |
1071 changed = true; | 1390 changed = true; |
1072 } | 1391 } |
1073 } | 1392 } |
1074 | 1393 |
1075 // Update the OnChangedStat and dispatch the event if something significant | 1394 // Update the OnChangedStat and dispatch the event if something significant |
1076 // changed. Replace the stored json with the new json. | 1395 // changed. Replace the stored json with the new json. |
1077 data->OnItemUpdated(); | 1396 data->OnItemUpdated(); |
1078 if (changed) { | 1397 if (changed) { |
1079 DispatchEvent(extensions::event_names::kOnDownloadChanged, delta.release()); | 1398 DispatchEvent(extensions::event_names::kOnDownloadChanged, |
1399 true, | |
1400 delta.release()); | |
1080 data->OnChangedFired(); | 1401 data->OnChangedFired(); |
1081 } | 1402 } |
1082 data->set_json(new_json.Pass()); | 1403 data->set_json(new_json.Pass()); |
1083 } | 1404 } |
1084 | 1405 |
1085 void ExtensionDownloadsEventRouter::OnDownloadRemoved( | 1406 void ExtensionDownloadsEventRouter::OnDownloadRemoved( |
1086 DownloadManager* manager, DownloadItem* download_item) { | 1407 DownloadManager* manager, DownloadItem* download_item) { |
1087 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1088 if (download_item->IsTemporary()) | 1409 if (download_item->IsTemporary()) |
1089 return; | 1410 return; |
1090 DispatchEvent(extensions::event_names::kOnDownloadErased, | 1411 DispatchEvent(extensions::event_names::kOnDownloadErased, |
1412 true, | |
1091 base::Value::CreateIntegerValue(download_item->GetId())); | 1413 base::Value::CreateIntegerValue(download_item->GetId())); |
1092 } | 1414 } |
1093 | 1415 |
1094 void ExtensionDownloadsEventRouter::DispatchEvent( | 1416 void ExtensionDownloadsEventRouter::DispatchEvent( |
1095 const char* event_name, base::Value* arg) { | 1417 const char* event_name, bool include_incognito, base::Value* arg) { |
1096 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1097 scoped_ptr<base::ListValue> args(new base::ListValue()); | 1419 scoped_ptr<base::ListValue> args(new base::ListValue()); |
1098 args->Append(arg); | 1420 args->Append(arg); |
1099 std::string json_args; | 1421 std::string json_args; |
1100 base::JSONWriter::Write(args.get(), &json_args); | 1422 base::JSONWriter::Write(args.get(), &json_args); |
1101 // There is a one EDER for each on-record Profile, and a separate EDER for | 1423 // There is a one EDER for each on-record Profile, and a separate EDER for |
1102 // each off-record Profile, so there is exactly one EDER for each | 1424 // each off-record Profile, so there is exactly one EDER for each |
1103 // DownloadManager. EDER only watches its own DM, so all the items that an | 1425 // DownloadManager. EDER only watches its own DM, so all the items that an |
1104 // EDER sees are either all on-record or all off-record. However, we want | 1426 // EDER sees are either all on-record or all off-record. However, extensions |
1105 // extensions in off-record contexts to see on-record items. So, if this EDER | 1427 // in off-record contexts should see on-record items. So, if this EDER is |
1106 // is watching an on-record DM, and there is a corresponding off-record | 1428 // watching an on-record DM, and there is a corresponding off-record Profile, |
1107 // Profile, then dispatch this event to both the on-record Profile and the | 1429 // then dispatch this event to both the on-record Profile and the off-record |
1108 // off-record Profile. There may or may not be an off-record Profile, so send | 1430 // Profile. There may or may not be an off-record Profile, so send a *copy* |
1109 // a *copy* of |args| to the off-record Profile, and Pass() |args| | 1431 // of |args| to the off-record Profile, and Pass() |args| to the Profile that |
1110 // to the Profile that we know is there. | 1432 // is certainly there. |
1111 if (profile_->HasOffTheRecordProfile() && | 1433 if (include_incognito && |
1434 profile_->HasOffTheRecordProfile() && | |
1112 !profile_->IsOffTheRecord()) { | 1435 !profile_->IsOffTheRecord()) { |
1113 DispatchEventInternal( | 1436 DispatchEventInternal( |
1114 profile_->GetOffTheRecordProfile(), | 1437 profile_->GetOffTheRecordProfile(), |
1115 event_name, | 1438 event_name, |
1116 json_args, | 1439 json_args, |
1117 scoped_ptr<base::ListValue>(args->DeepCopy())); | 1440 scoped_ptr<base::ListValue>(args->DeepCopy())); |
1118 } | 1441 } |
1119 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); | 1442 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); |
1120 } | 1443 } |
OLD | NEW |