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" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { | 174 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { |
174 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { | 175 for (size_t i = 0; i < arraysize(kStateStrings); ++i) { |
175 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) | 176 if ((kStateStrings[i] != NULL) && (state == kStateStrings[i])) |
176 return static_cast<DownloadItem::DownloadState>(i); | 177 return static_cast<DownloadItem::DownloadState>(i); |
177 } | 178 } |
178 return DownloadItem::MAX_DOWNLOAD_STATE; | 179 return DownloadItem::MAX_DOWNLOAD_STATE; |
179 } | 180 } |
180 | 181 |
181 bool ValidateFilename(const string16& filename) { | 182 bool ValidateFilename(const string16& filename) { |
182 // TODO(benjhayden): More robust validation of filename. | 183 // TODO(benjhayden): More robust validation of filename. |
184 if (filename.size() < 1) | |
battre
2013/01/11 14:29:37
nit: why not
if (filename.empty())
?
benjhayden
2013/01/11 21:21:27
Done.
| |
185 return false; | |
183 if ((filename.find('/') != string16::npos) || | 186 if ((filename.find('/') != string16::npos) || |
184 (filename.find('\\') != string16::npos)) | 187 (filename.find('\\') != string16::npos)) |
185 return false; | 188 return false; |
186 if (filename.size() >= 2u && filename[0] == L'.' && filename[1] == L'.') | 189 if (filename.size() >= 2u && filename[0] == L'.' && filename[1] == L'.') |
187 return false; | 190 return false; |
188 return true; | 191 return true; |
189 } | 192 } |
190 | 193 |
191 std::string TimeToISO8601(const base::Time& t) { | 194 std::string TimeToISO8601(const base::Time& t) { |
192 base::Time::Exploded exploded; | 195 base::Time::Exploded exploded; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
249 }; | 252 }; |
250 | 253 |
251 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( | 254 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( |
252 const FilePath& path, | 255 const FilePath& path, |
253 IconLoader::IconSize icon_size, | 256 IconLoader::IconSize icon_size, |
254 IconURLCallback callback) { | 257 IconURLCallback callback) { |
255 callback_ = callback; | 258 callback_ = callback; |
256 IconManager* im = g_browser_process->icon_manager(); | 259 IconManager* im = g_browser_process->icon_manager(); |
257 // The contents of the file at |path| may have changed since a previous | 260 // The contents of the file at |path| may have changed since a previous |
258 // request, in which case the associated icon may also have changed. | 261 // request, in which case the associated icon may also have changed. |
259 // Therefore, for the moment we always call LoadIcon instead of attempting | 262 // Therefore, always call LoadIcon instead of attempting a LookupIcon. |
260 // a LookupIcon. | |
261 im->LoadIcon(path, | 263 im->LoadIcon(path, |
262 icon_size, | 264 icon_size, |
263 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, | 265 base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, |
264 base::Unretained(this)), | 266 base::Unretained(this)), |
265 &cancelable_task_tracker_); | 267 &cancelable_task_tracker_); |
266 return true; | 268 return true; |
267 } | 269 } |
268 | 270 |
269 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { | 271 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) { |
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
529 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); | 531 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); |
530 return (data == NULL) ? NULL : | 532 return (data == NULL) ? NULL : |
531 static_cast<ExtensionDownloadsEventRouterData*>(data); | 533 static_cast<ExtensionDownloadsEventRouterData*>(data); |
532 } | 534 } |
533 | 535 |
534 explicit ExtensionDownloadsEventRouterData( | 536 explicit ExtensionDownloadsEventRouterData( |
535 DownloadItem* download_item, | 537 DownloadItem* download_item, |
536 scoped_ptr<base::DictionaryValue> json_item) | 538 scoped_ptr<base::DictionaryValue> json_item) |
537 : updated_(0), | 539 : updated_(0), |
538 changed_fired_(0), | 540 changed_fired_(0), |
539 json_(json_item.Pass()) { | 541 json_(json_item.Pass()), |
542 determined_overwrite_(false) { | |
540 download_item->SetUserData(kKey, this); | 543 download_item->SetUserData(kKey, this); |
541 } | 544 } |
542 | 545 |
543 virtual ~ExtensionDownloadsEventRouterData() { | 546 virtual ~ExtensionDownloadsEventRouterData() { |
544 if (updated_ > 0) { | 547 if (updated_ > 0) { |
545 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", | 548 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", |
546 (changed_fired_ * 100 / updated_)); | 549 (changed_fired_ * 100 / updated_)); |
547 } | 550 } |
548 } | 551 } |
549 | 552 |
550 const base::DictionaryValue& json() const { return *json_.get(); } | 553 const base::DictionaryValue& json() const { return *json_.get(); } |
551 void set_json(scoped_ptr<base::DictionaryValue> json_item) { | 554 void set_json(scoped_ptr<base::DictionaryValue> json_item) { |
552 json_ = json_item.Pass(); | 555 json_ = json_item.Pass(); |
553 } | 556 } |
554 | 557 |
555 void OnItemUpdated() { ++updated_; } | 558 void OnItemUpdated() { ++updated_; } |
556 void OnChangedFired() { ++changed_fired_; } | 559 void OnChangedFired() { ++changed_fired_; } |
557 | 560 |
561 void set_filename_change_callbacks( | |
562 const base::Closure& no_change, | |
563 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { | |
564 filename_no_change_ = no_change; | |
565 filename_change_ = change; | |
566 } | |
567 | |
568 void AddDeterminer(const std::string& determiner_id) { | |
battre
2013/01/11 14:29:37
How about "AddPendingDeterminer"?
benjhayden
2013/01/11 21:21:27
Done.
| |
569 DCHECK(determiners_.insert(determiner_id).second); | |
570 } | |
571 | |
572 bool DetermineFilename( | |
battre
2013/01/11 14:29:37
How about "DeterminerCallback"
benjhayden
2013/01/11 21:21:27
Done.
| |
573 const std::string& determiner_id, | |
574 const FilePath& filename, | |
575 bool overwrite) { | |
576 DeterminerSet::iterator iter = determiners_.find(determiner_id); | |
577 if (iter == determiners_.end()) | |
578 return false; | |
579 determiners_.erase(iter); | |
battre
2013/01/11 14:29:37
This looks strange. DetermineFilename should not m
benjhayden
2013/01/11 21:21:27
This is the method that runs when any onDeterminin
| |
580 if (!filename.empty() && !filename.IsAbsolute()) { | |
581 determined_filename_ = filename; | |
582 determined_overwrite_ = overwrite; | |
583 } | |
584 if (determiners_.empty()) { | |
585 if (determined_filename_.empty()) { | |
586 filename_no_change_.Run(); | |
587 } else { | |
588 filename_change_.Run(determined_filename_, determined_overwrite_); | |
589 } | |
590 } | |
battre
2013/01/11 14:29:37
This is "Last callback wins" semantic. In the WebR
benjhayden
2013/01/11 21:21:27
Done.
| |
591 return true; | |
592 } | |
593 | |
558 private: | 594 private: |
595 typedef std::set<std::string> DeterminerSet; | |
596 | |
559 static const char kKey[]; | 597 static const char kKey[]; |
560 | 598 |
561 int updated_; | 599 int updated_; |
562 int changed_fired_; | 600 int changed_fired_; |
563 scoped_ptr<base::DictionaryValue> json_; | 601 scoped_ptr<base::DictionaryValue> json_; |
602 base::Closure filename_no_change_; | |
603 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_; | |
604 FilePath determined_filename_; | |
605 bool determined_overwrite_; | |
606 DeterminerSet determiners_; | |
564 | 607 |
565 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); | 608 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); |
566 }; | 609 }; |
567 | 610 |
568 const char ExtensionDownloadsEventRouterData::kKey[] = | 611 const char ExtensionDownloadsEventRouterData::kKey[] = |
569 "DownloadItem ExtensionDownloadsEventRouterData"; | 612 "DownloadItem ExtensionDownloadsEventRouterData"; |
570 | 613 |
571 } // namespace | 614 } // namespace |
572 | 615 |
573 DownloadsDownloadFunction::DownloadsDownloadFunction() {} | 616 DownloadsDownloadFunction::DownloadsDownloadFunction() {} |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
732 extensions::api::downloads::Resume::Params::Create(*args_)); | 775 extensions::api::downloads::Resume::Params::Create(*args_)); |
733 EXTENSION_FUNCTION_VALIDATE(params.get()); | 776 EXTENSION_FUNCTION_VALIDATE(params.get()); |
734 DownloadItem* download_item = GetDownloadIfInProgress( | 777 DownloadItem* download_item = GetDownloadIfInProgress( |
735 profile(), include_incognito(), params->download_id); | 778 profile(), include_incognito(), params->download_id); |
736 if (download_item == NULL) { | 779 if (download_item == NULL) { |
737 // This could be due to an invalid download ID, or it could be due to the | 780 // This could be due to an invalid download ID, or it could be due to the |
738 // download not being currently active. | 781 // download not being currently active. |
739 error_ = download_extension_errors::kInvalidOperationError; | 782 error_ = download_extension_errors::kInvalidOperationError; |
740 } else { | 783 } else { |
741 // Note that if the item isn't paused, this will be a no-op, and | 784 // Note that if the item isn't paused, this will be a no-op, and |
742 // we will silently treat the extension call as a success. | 785 // the extension call will seem successful. |
743 download_item->Resume(); | 786 download_item->Resume(); |
744 } | 787 } |
745 if (error_.empty()) | 788 if (error_.empty()) |
746 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); | 789 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME); |
747 return error_.empty(); | 790 return error_.empty(); |
748 } | 791 } |
749 | 792 |
750 DownloadsCancelFunction::DownloadsCancelFunction() {} | 793 DownloadsCancelFunction::DownloadsCancelFunction() {} |
751 DownloadsCancelFunction::~DownloadsCancelFunction() {} | 794 DownloadsCancelFunction::~DownloadsCancelFunction() {} |
752 | 795 |
753 bool DownloadsCancelFunction::RunImpl() { | 796 bool DownloadsCancelFunction::RunImpl() { |
754 scoped_ptr<extensions::api::downloads::Resume::Params> params( | 797 scoped_ptr<extensions::api::downloads::Resume::Params> params( |
755 extensions::api::downloads::Resume::Params::Create(*args_)); | 798 extensions::api::downloads::Resume::Params::Create(*args_)); |
756 EXTENSION_FUNCTION_VALIDATE(params.get()); | 799 EXTENSION_FUNCTION_VALIDATE(params.get()); |
757 DownloadItem* download_item = GetDownloadIfInProgress( | 800 DownloadItem* download_item = GetDownloadIfInProgress( |
758 profile(), include_incognito(), params->download_id); | 801 profile(), include_incognito(), params->download_id); |
759 if (download_item != NULL) | 802 if (download_item != NULL) |
760 download_item->Cancel(true); | 803 download_item->Cancel(true); |
761 // |download_item| can be NULL if the download ID was invalid or if the | 804 // |download_item| can be NULL if the download ID was invalid or if the |
762 // download is not currently active. Either way, we don't consider it a | 805 // download is not currently active. Either way, it's not a failure. |
763 // failure. | |
764 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); | 806 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); |
765 return true; | 807 return true; |
766 } | 808 } |
767 | 809 |
768 DownloadsEraseFunction::DownloadsEraseFunction() {} | 810 DownloadsEraseFunction::DownloadsEraseFunction() {} |
769 DownloadsEraseFunction::~DownloadsEraseFunction() {} | 811 DownloadsEraseFunction::~DownloadsEraseFunction() {} |
770 | 812 |
771 bool DownloadsEraseFunction::RunImpl() { | 813 bool DownloadsEraseFunction::RunImpl() { |
772 scoped_ptr<extensions::api::downloads::Erase::Params> params( | 814 scoped_ptr<extensions::api::downloads::Erase::Params> params( |
773 extensions::api::downloads::Erase::Params::Create(*args_)); | 815 extensions::api::downloads::Erase::Params::Create(*args_)); |
(...skipping 13 matching lines...) Expand all Loading... | |
787 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); | 829 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); |
788 it != results.end(); ++it) { | 830 it != results.end(); ++it) { |
789 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); | 831 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); |
790 (*it)->Remove(); | 832 (*it)->Remove(); |
791 } | 833 } |
792 SetResult(json_results); | 834 SetResult(json_results); |
793 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); | 835 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); |
794 return true; | 836 return true; |
795 } | 837 } |
796 | 838 |
797 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() {} | |
798 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} | |
799 | |
800 bool DownloadsSetDestinationFunction::RunImpl() { | |
801 scoped_ptr<extensions::api::downloads::SetDestination::Params> params( | |
802 extensions::api::downloads::SetDestination::Params::Create(*args_)); | |
803 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
804 error_ = download_extension_errors::kNotImplementedError; | |
805 if (error_.empty()) | |
806 RecordApiFunctions(DOWNLOADS_FUNCTION_SET_DESTINATION); | |
807 return error_.empty(); | |
808 } | |
809 | |
810 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} | 839 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} |
811 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} | 840 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} |
812 | 841 |
813 bool DownloadsAcceptDangerFunction::RunImpl() { | 842 bool DownloadsAcceptDangerFunction::RunImpl() { |
814 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( | 843 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( |
815 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); | 844 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); |
816 EXTENSION_FUNCTION_VALIDATE(params.get()); | 845 EXTENSION_FUNCTION_VALIDATE(params.get()); |
817 error_ = download_extension_errors::kNotImplementedError; | 846 error_ = download_extension_errors::kNotImplementedError; |
818 if (error_.empty()) | 847 if (error_.empty()) |
819 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER); | 848 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 int icon_size = kDefaultIconSize; | 933 int icon_size = kDefaultIconSize; |
905 if (options && options->size.get()) | 934 if (options && options->size.get()) |
906 icon_size = *options->size.get(); | 935 icon_size = *options->size.get(); |
907 DownloadItem* download_item = GetDownload( | 936 DownloadItem* download_item = GetDownload( |
908 profile(), include_incognito(), params->download_id); | 937 profile(), include_incognito(), params->download_id); |
909 if (!download_item || download_item->GetTargetFilePath().empty()) { | 938 if (!download_item || download_item->GetTargetFilePath().empty()) { |
910 error_ = download_extension_errors::kInvalidOperationError; | 939 error_ = download_extension_errors::kInvalidOperationError; |
911 return false; | 940 return false; |
912 } | 941 } |
913 // In-progress downloads return the intermediate filename for GetFullPath() | 942 // In-progress downloads return the intermediate filename for GetFullPath() |
914 // which doesn't have the final extension. Therefore we won't be able to | 943 // which doesn't have the final extension. Therefore a good file icon can't be |
915 // derive a good file icon for it. So we use GetTargetFilePath() instead. | 944 // found, so use GetTargetFilePath() instead. |
916 DCHECK(icon_extractor_.get()); | 945 DCHECK(icon_extractor_.get()); |
917 DCHECK(icon_size == 16 || icon_size == 32); | 946 DCHECK(icon_size == 16 || icon_size == 32); |
918 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( | 947 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( |
919 download_item->GetTargetFilePath(), | 948 download_item->GetTargetFilePath(), |
920 IconLoaderSizeFromPixelSize(icon_size), | 949 IconLoaderSizeFromPixelSize(icon_size), |
921 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); | 950 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); |
922 return true; | 951 return true; |
923 } | 952 } |
924 | 953 |
925 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { | 954 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { |
926 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 955 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
927 if (url.empty()) { | 956 if (url.empty()) { |
928 error_ = download_extension_errors::kIconNotFoundError; | 957 error_ = download_extension_errors::kIconNotFoundError; |
929 } else { | 958 } else { |
930 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); | 959 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON); |
931 SetResult(base::Value::CreateStringValue(url)); | 960 SetResult(base::Value::CreateStringValue(url)); |
932 } | 961 } |
933 SendResponse(error_.empty()); | 962 SendResponse(error_.empty()); |
934 } | 963 } |
935 | 964 |
965 // The method by which extensions hook into the filename determination process | |
966 // is based on the method by which the webRequest API allows extensions to hook | |
967 // into the resource loading process. Extensions that wish to play a part in | |
968 // the filename determination process call | |
969 // chrome.downloads.onDeterminingFilename.addListener, which secretly (see | |
970 // chrome/renderer/resources/extensions/downloads_custom_bindings.js) calls | |
971 // DownloadsInternalAddFilenameDeterminerFunction (see ../downloads_internal/), | |
972 // which adds the extension's ID to the profile's ExtensionDownloadsEventRouter | |
973 // (EDER). When a download's filename is being determined, | |
974 // ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone (CVRBD) passes | |
975 // 2 callbacks to EDER::OnDownloadFilenameDetermined (ODFD), which stores the | |
976 // callbacks in the item's ExtensionDownloadsEventRouterData (EDERD) along with | |
977 // all of the extension IDs that are listening for onDeterminingFilename events. | |
978 // ODFD dispatches chrome.downloads.onDeterminingFilename. When the extension's | |
979 // event handler returns, downloads_custom_bindings.js calls | |
980 // DownloadsInternalDetermineFilenameFunction::RunImpl, which notifies the | |
981 // item's EDERD. When the last extension's event handler returns, EDERD calls | |
982 // one of the two callbacks that CVRBD passed to ODFD, allowing CDMD to complete | |
983 // the filename determination process. If multiple extensions wish to override | |
984 // the filename, then the last one wins. However, there's no deterministic way | |
985 // to determine which extension will finish last, so users are advised to try to | |
vabr (Chromium)
2013/01/11 12:43:40
How precisely are the users advised? Using the Ext
benjhayden
2013/01/11 21:21:27
Oh, I was just going to make a note in downloads.i
vabr (Chromium)
2013/01/15 08:19:22
The analogy in WebRequest is, e.g., when two exten
battre
2013/01/15 09:00:40
Please don't add a warning badge for this. I think
| |
986 // use extensions that won't conflict. | |
987 | |
988 bool ExtensionDownloadsEventRouter::AddFilenameDeterminer( | |
989 Profile* profile, | |
990 bool include_incognito, | |
991 const std::string& ext_id, | |
992 const std::string& determiner_id) { | |
993 if (include_incognito && profile->HasOffTheRecordProfile()) { | |
994 AddFilenameDeterminer(profile->GetOffTheRecordProfile(), | |
995 false, | |
996 ext_id, | |
997 determiner_id); | |
998 } | |
999 ExtensionDownloadsEventRouter* router = | |
1000 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); | |
vabr (Chromium)
2013/01/11 12:43:40
+2 spaces of indentation
benjhayden
2013/01/11 21:21:27
Done.
| |
1001 return router->filename_determiners_[determiner_id].insert(ext_id).second; | |
1002 } | |
1003 | |
1004 bool ExtensionDownloadsEventRouter::RemoveFilenameDeterminer( | |
1005 Profile* profile, | |
1006 bool include_incognito, | |
1007 const std::string& ext_id, | |
1008 const std::string& determiner_id) { | |
1009 if (include_incognito && profile->HasOffTheRecordProfile()) { | |
1010 RemoveFilenameDeterminer(profile->GetOffTheRecordProfile(), | |
1011 false, | |
1012 ext_id, | |
1013 determiner_id); | |
1014 } | |
1015 ExtensionDownloadsEventRouter* router = | |
1016 DownloadServiceFactory::GetForProfile(profile)->GetExtensionEventRouter(); | |
vabr (Chromium)
2013/01/11 12:43:40
+2 spaces of indentation
benjhayden
2013/01/11 21:21:27
Done.
| |
1017 DeterminerMap::iterator determiner_entry( | |
1018 router->filename_determiners_.find(determiner_id)); | |
1019 DCHECK(determiner_entry != router->filename_determiners_.end()); | |
1020 if (determiner_entry == router->filename_determiners_.end()) | |
1021 return false; | |
1022 ExtensionIdSet::iterator extension_entry( | |
1023 router->filename_determiners_[determiner_id].find(ext_id)); | |
1024 DCHECK(extension_entry != router->filename_determiners_[determiner_id].end()); | |
1025 if (extension_entry == router->filename_determiners_[determiner_id].end()) | |
1026 return false; | |
1027 router->filename_determiners_[determiner_id].erase(extension_entry); | |
1028 if (router->filename_determiners_[determiner_id].empty()) | |
1029 router->filename_determiners_.erase(determiner_entry); | |
1030 return true; | |
1031 } | |
1032 | |
1033 bool ExtensionDownloadsEventRouter::DetermineFilename( | |
1034 Profile* profile, | |
1035 bool include_incognito, | |
1036 const std::string& ext_id, | |
1037 const std::string& determiner_id, | |
1038 int download_id, | |
1039 const FilePath& filename, | |
1040 bool overwrite) { | |
1041 DownloadItem* item = GetDownloadIfInProgress( | |
1042 profile, include_incognito, download_id); | |
1043 if (!item) | |
1044 return false; | |
1045 ExtensionDownloadsEventRouterData* data = | |
1046 ExtensionDownloadsEventRouterData::Get(item); | |
vabr (Chromium)
2013/01/11 12:43:40
+2 spaces of indentation
benjhayden
2013/01/11 21:21:27
Done.
| |
1047 if (!data) | |
1048 return false; | |
1049 return data->DetermineFilename( | |
1050 ext_id + "-" + determiner_id, filename, overwrite); | |
1051 } | |
1052 | |
936 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( | 1053 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
937 Profile* profile, | 1054 Profile* profile, |
938 DownloadManager* manager) | 1055 DownloadManager* manager) |
939 : profile_(profile), | 1056 : profile_(profile), |
940 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { | 1057 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { |
941 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1058 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
942 DCHECK(profile_); | 1059 DCHECK(profile_); |
1060 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
1061 content::Source<Profile>(profile_)); | |
1062 } | |
1063 | |
1064 void ExtensionDownloadsEventRouter::Observe( | |
1065 int type, | |
1066 const content::NotificationSource& source, | |
1067 const content::NotificationDetails& details) { | |
1068 switch (type) { | |
1069 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | |
1070 const extensions::Extension* extension = content::Details< | |
1071 extensions::UnloadedExtensionInfo>(details)->extension; | |
vabr (Chromium)
2013/01/11 12:43:40
+2 spaces of indent
benjhayden
2013/01/11 21:21:27
Done.
| |
1072 std::set<std::string> empty_determiners; | |
1073 for (DeterminerMap::iterator | |
1074 determiner_iter = filename_determiners_.begin(); | |
1075 determiner_iter != filename_determiners_.end(); | |
1076 ++determiner_iter) { | |
1077 ExtensionIdSet::iterator found(determiner_iter->second.find( | |
1078 extension->id())); | |
1079 if (found != determiner_iter->second.end()) { | |
1080 determiner_iter->second.erase(found); | |
1081 if (determiner_iter->second.empty()) | |
1082 empty_determiners.insert(determiner_iter->first); | |
1083 } | |
1084 } | |
1085 for (std::set<std::string>::const_iterator | |
1086 iter = empty_determiners.begin(); | |
vabr (Chromium)
2013/01/11 12:43:40
+4 spaces of indent
nit: please break after "=", n
benjhayden
2013/01/11 21:21:27
Done.
| |
1087 iter != empty_determiners.end(); | |
1088 ++iter) { | |
1089 DeterminerMap::iterator found = filename_determiners_.find(*iter); | |
1090 CHECK(found != filename_determiners_.end()); | |
1091 filename_determiners_.erase(found); | |
1092 } | |
1093 break; | |
1094 } | |
1095 default: | |
1096 NOTREACHED(); | |
1097 break; | |
1098 } | |
943 } | 1099 } |
944 | 1100 |
945 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | 1101 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
946 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
947 } | 1103 } |
948 | 1104 |
949 void ExtensionDownloadsEventRouter::OnDownloadCreated( | 1105 void ExtensionDownloadsEventRouter::OnDownloadCreated( |
950 DownloadManager* manager, DownloadItem* download_item) { | 1106 DownloadManager* manager, DownloadItem* download_item) { |
951 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
952 if (download_item->IsTemporary()) | 1108 if (download_item->IsTemporary()) |
953 return; | 1109 return; |
954 | 1110 |
955 scoped_ptr<base::DictionaryValue> json_item( | 1111 scoped_ptr<base::DictionaryValue> json_item( |
956 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); | 1112 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
957 DispatchEvent(extensions::event_names::kOnDownloadCreated, | 1113 DispatchEvent(extensions::event_names::kOnDownloadCreated, |
958 json_item->DeepCopy()); | 1114 json_item->DeepCopy()); |
959 if (!ExtensionDownloadsEventRouterData::Get(download_item)) | 1115 if (!ExtensionDownloadsEventRouterData::Get(download_item)) |
960 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); | 1116 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); |
961 } | 1117 } |
962 | 1118 |
1119 void ExtensionDownloadsEventRouter::OnDownloadFilenameDetermined( | |
1120 DownloadItem* item, | |
1121 const FilePath& suggested_path, | |
1122 const base::Closure& no_change, | |
1123 const FilenameChangedCallback& change) { | |
1124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1125 if (filename_determiners_.empty()) { | |
1126 no_change.Run(); | |
1127 return; | |
1128 } | |
1129 | |
1130 ExtensionDownloadsEventRouterData* data = | |
1131 ExtensionDownloadsEventRouterData::Get(item); | |
vabr (Chromium)
2013/01/11 12:43:40
+2 spaces of indent
benjhayden
2013/01/11 21:21:27
Done.
| |
1132 data->set_filename_change_callbacks(no_change, change); | |
1133 std::string event_name( | |
1134 extensions::event_names::kOnDownloadDeterminingFilename); | |
1135 event_name += "/"; | |
1136 for (DeterminerMap::const_iterator | |
1137 determiner_iter = filename_determiners_.begin(); | |
vabr (Chromium)
2013/01/11 12:43:40
+4 spaces
nit: please break after "="
benjhayden
2013/01/11 21:21:27
Done.
| |
1138 determiner_iter != filename_determiners_.end(); | |
1139 ++determiner_iter) { | |
1140 const std::string& determiner_id = determiner_iter->first; | |
1141 for (ExtensionIdSet::const_iterator | |
1142 ext_iter = determiner_iter->second.begin(); | |
1143 ext_iter != determiner_iter->second.end(); | |
1144 ++ext_iter) { | |
1145 data->AddDeterminer((*ext_iter) + "-" + determiner_id); | |
1146 } | |
1147 base::DictionaryValue* json = DownloadItemToJSON( | |
1148 item, profile_->IsOffTheRecord()).release(); | |
1149 json->SetString( | |
1150 kFilenameKey, suggested_path.LossyDisplayName()); | |
1151 DispatchEvent( | |
1152 (event_name + determiner_id).c_str(), | |
1153 json); | |
1154 } | |
1155 } | |
1156 | |
963 void ExtensionDownloadsEventRouter::OnDownloadUpdated( | 1157 void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
964 DownloadManager* manager, DownloadItem* download_item) { | 1158 DownloadManager* manager, DownloadItem* download_item) { |
965 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
966 if (download_item->IsTemporary()) | 1160 if (download_item->IsTemporary()) |
967 return; | 1161 return; |
968 | 1162 |
969 ExtensionDownloadsEventRouterData* data = | 1163 ExtensionDownloadsEventRouterData* data = |
970 ExtensionDownloadsEventRouterData::Get(download_item); | 1164 ExtensionDownloadsEventRouterData::Get(download_item); |
971 if (!data) { | 1165 if (!data) { |
972 // The download_item probably transitioned from temporary to not temporary. | 1166 // The download_item probably transitioned from temporary to not temporary. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1032 void ExtensionDownloadsEventRouter::DispatchEvent( | 1226 void ExtensionDownloadsEventRouter::DispatchEvent( |
1033 const char* event_name, base::Value* arg) { | 1227 const char* event_name, base::Value* arg) { |
1034 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1035 scoped_ptr<base::ListValue> args(new base::ListValue()); | 1229 scoped_ptr<base::ListValue> args(new base::ListValue()); |
1036 args->Append(arg); | 1230 args->Append(arg); |
1037 std::string json_args; | 1231 std::string json_args; |
1038 base::JSONWriter::Write(args.get(), &json_args); | 1232 base::JSONWriter::Write(args.get(), &json_args); |
1039 // There is a one EDER for each on-record Profile, and a separate EDER for | 1233 // There is a one EDER for each on-record Profile, and a separate EDER for |
1040 // each off-record Profile, so there is exactly one EDER for each | 1234 // each off-record Profile, so there is exactly one EDER for each |
1041 // DownloadManager. EDER only watches its own DM, so all the items that an | 1235 // DownloadManager. EDER only watches its own DM, so all the items that an |
1042 // EDER sees are either all on-record or all off-record. However, we want | 1236 // EDER sees are either all on-record or all off-record. However, extensions |
1043 // extensions in off-record contexts to see on-record items. So, if this EDER | 1237 // in off-record contexts should see on-record items. So, if this EDER is |
1044 // is watching an on-record DM, and there is a corresponding off-record | 1238 // watching an on-record DM, and there is a corresponding off-record Profile, |
1045 // Profile, then dispatch this event to both the on-record Profile and the | 1239 // then dispatch this event to both the on-record Profile and the off-record |
1046 // off-record Profile. There may or may not be an off-record Profile, so send | 1240 // Profile. There may or may not be an off-record Profile, so send a *copy* |
1047 // a *copy* of |args| to the off-record Profile, and Pass() |args| | 1241 // of |args| to the off-record Profile, and Pass() |args| to the Profile that |
1048 // to the Profile that we know is there. | 1242 // is certainly there. |
1049 if (profile_->HasOffTheRecordProfile() && | 1243 if (profile_->HasOffTheRecordProfile() && |
1050 !profile_->IsOffTheRecord()) { | 1244 !profile_->IsOffTheRecord()) { |
1051 DispatchEventInternal( | 1245 DispatchEventInternal( |
1052 profile_->GetOffTheRecordProfile(), | 1246 profile_->GetOffTheRecordProfile(), |
1053 event_name, | 1247 event_name, |
1054 json_args, | 1248 json_args, |
1055 scoped_ptr<base::ListValue>(args->DeepCopy())); | 1249 scoped_ptr<base::ListValue>(args->DeepCopy())); |
1056 } | 1250 } |
1057 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); | 1251 DispatchEventInternal(profile_, event_name, json_args, args.Pass()); |
1058 } | 1252 } |
OLD | NEW |