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