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

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 11574006: Implement chrome.downloads.onDeterminingFilename() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r176065 Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cctype> 8 #include <cctype>
9 #include <iterator> 9 #include <iterator>
10 #include <set> 10 #include <set>
11 #include <string> 11 #include <string>
12 12
13 #include "base/basictypes.h" 13 #include "base/basictypes.h"
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/bind_helpers.h" 15 #include "base/bind_helpers.h"
16 #include "base/callback.h" 16 #include "base/callback.h"
17 #include "base/file_path.h"
17 #include "base/json/json_writer.h" 18 #include "base/json/json_writer.h"
18 #include "base/lazy_instance.h" 19 #include "base/lazy_instance.h"
19 #include "base/logging.h" 20 #include "base/logging.h"
20 #include "base/metrics/histogram.h" 21 #include "base/metrics/histogram.h"
21 #include "base/stl_util.h" 22 #include "base/stl_util.h"
22 #include "base/string16.h" 23 #include "base/string16.h"
23 #include "base/string_split.h" 24 #include "base/string_split.h"
24 #include "base/string_util.h" 25 #include "base/string_util.h"
25 #include "base/stringprintf.h" 26 #include "base/stringprintf.h"
26 #include "base/values.h" 27 #include "base/values.h"
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698