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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/downloads_dom_handler.h" 6 7 #include <algorithm> 8 #include <functional> 9 10 #include "base/basictypes.h" 11 #include "base/bind.h" 12 #include "base/bind_helpers.h" 13 #include "base/i18n/rtl.h" 14 #include "base/i18n/time_formatting.h" 15 #include "base/memory/singleton.h" 16 #include "base/metrics/field_trial.h" 17 #include "base/metrics/histogram.h" 18 #include "base/prefs/pref_service.h" 19 #include "base/strings/string_piece.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/threading/thread.h" 22 #include "base/value_conversions.h" 23 #include "base/values.h" 24 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/download/download_crx_util.h" 26 #include "chrome/browser/download/download_danger_prompt.h" 27 #include "chrome/browser/download/download_history.h" 28 #include "chrome/browser/download/download_item_model.h" 29 #include "chrome/browser/download/download_prefs.h" 30 #include "chrome/browser/download/download_query.h" 31 #include "chrome/browser/download/download_service.h" 32 #include "chrome/browser/download/download_service_factory.h" 33 #include "chrome/browser/download/drag_download_item.h" 34 #include "chrome/browser/extensions/api/downloads/downloads_api.h" 35 #include "chrome/browser/extensions/extension_service.h" 36 #include "chrome/browser/platform_util.h" 37 #include "chrome/browser/profiles/profile.h" 38 #include "chrome/browser/ui/webui/fileicon_source.h" 39 #include "chrome/common/pref_names.h" 40 #include "chrome/common/url_constants.h" 41 #include "content/public/browser/browser_thread.h" 42 #include "content/public/browser/download_item.h" 43 #include "content/public/browser/url_data_source.h" 44 #include "content/public/browser/user_metrics.h" 45 #include "content/public/browser/web_contents.h" 46 #include "content/public/browser/web_ui.h" 47 #include "extensions/browser/extension_system.h" 48 #include "net/base/filename_util.h" 49 #include "ui/base/l10n/time_format.h" 50 #include "ui/gfx/image/image.h" 51 52 using base::UserMetricsAction; 53 using content::BrowserContext; 54 using content::BrowserThread; 55 56 namespace { 57 58 // Maximum number of downloads to show. TODO(glen): Remove this and instead 59 // stuff the downloads down the pipe slowly. 60 static const size_t kMaxDownloads = 150; 61 62 enum DownloadsDOMEvent { 63 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, 64 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, 65 DOWNLOADS_DOM_EVENT_DRAG = 2, 66 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3, 67 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4, 68 DOWNLOADS_DOM_EVENT_SHOW = 5, 69 DOWNLOADS_DOM_EVENT_PAUSE = 6, 70 DOWNLOADS_DOM_EVENT_REMOVE = 7, 71 DOWNLOADS_DOM_EVENT_CANCEL = 8, 72 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9, 73 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10, 74 DOWNLOADS_DOM_EVENT_RESUME = 11, 75 DOWNLOADS_DOM_EVENT_MAX 76 }; 77 78 void CountDownloadsDOMEvents(DownloadsDOMEvent event) { 79 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", 80 event, 81 DOWNLOADS_DOM_EVENT_MAX); 82 } 83 84 // Returns a string constant to be used as the |danger_type| value in 85 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE, 86 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the 87 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|. 88 const char* GetDangerTypeString(content::DownloadDangerType danger_type) { 89 switch (danger_type) { 90 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: 91 return "DANGEROUS_FILE"; 92 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 93 return "DANGEROUS_URL"; 94 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 95 return "DANGEROUS_CONTENT"; 96 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: 97 return "UNCOMMON_CONTENT"; 98 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 99 return "DANGEROUS_HOST"; 100 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: 101 return "POTENTIALLY_UNWANTED"; 102 default: 103 // Don't return a danger type string if it is NOT_DANGEROUS or 104 // MAYBE_DANGEROUS_CONTENT. 105 NOTREACHED(); 106 return ""; 107 } 108 } 109 110 // Returns a JSON dictionary containing some of the attributes of |download|. 111 // The JSON dictionary will also have a field "id" set to |id|, and a field 112 // "otr" set to |incognito|. 113 base::DictionaryValue* CreateDownloadItemValue( 114 content::DownloadItem* download_item, 115 bool incognito) { 116 // TODO(asanka): Move towards using download_model here for getting status and 117 // progress. The difference currently only matters to Drive downloads and 118 // those don't show up on the downloads page, but should. 119 DownloadItemModel download_model(download_item); 120 121 // The items which are to be written into file_value are also described in 122 // chrome/browser/resources/downloads/downloads.js in @typedef for 123 // BackendDownloadObject. Please update it whenever you add or remove 124 // any keys in file_value. 125 base::DictionaryValue* file_value = new base::DictionaryValue(); 126 127 file_value->SetInteger( 128 "started", static_cast<int>(download_item->GetStartTime().ToTimeT())); 129 file_value->SetString( 130 "since_string", ui::TimeFormat::RelativeDate( 131 download_item->GetStartTime(), NULL)); 132 file_value->SetString( 133 "date_string", base::TimeFormatShortDate(download_item->GetStartTime())); 134 file_value->SetInteger("id", download_item->GetId()); 135 136 base::FilePath download_path(download_item->GetTargetFilePath()); 137 file_value->Set("file_path", base::CreateFilePathValue(download_path)); 138 file_value->SetString("file_url", 139 net::FilePathToFileURL(download_path).spec()); 140 141 extensions::DownloadedByExtension* by_ext = 142 extensions::DownloadedByExtension::Get(download_item); 143 if (by_ext) { 144 file_value->SetString("by_ext_id", by_ext->id()); 145 file_value->SetString("by_ext_name", by_ext->name()); 146 // Lookup the extension's current name() in case the user changed their 147 // language. This won't work if the extension was uninstalled, so the name 148 // might be the wrong language. 149 bool include_disabled = true; 150 const extensions::Extension* extension = extensions::ExtensionSystem::Get( 151 Profile::FromBrowserContext(download_item->GetBrowserContext()))-> 152 extension_service()->GetExtensionById(by_ext->id(), include_disabled); 153 if (extension) 154 file_value->SetString("by_ext_name", extension->name()); 155 } 156 157 // Keep file names as LTR. 158 base::string16 file_name = 159 download_item->GetFileNameToReportUser().LossyDisplayName(); 160 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); 161 file_value->SetString("file_name", file_name); 162 file_value->SetString("url", download_item->GetURL().spec()); 163 file_value->SetBoolean("otr", incognito); 164 file_value->SetInteger("total", static_cast<int>( 165 download_item->GetTotalBytes())); 166 file_value->SetBoolean("file_externally_removed", 167 download_item->GetFileExternallyRemoved()); 168 file_value->SetBoolean("retry", false); // Overridden below if needed. 169 file_value->SetBoolean("resume", download_item->CanResume()); 170 171 switch (download_item->GetState()) { 172 case content::DownloadItem::IN_PROGRESS: 173 if (download_item->IsDangerous()) { 174 file_value->SetString("state", "DANGEROUS"); 175 // These are the only danger states that the UI is equipped to handle. 176 DCHECK(download_item->GetDangerType() == 177 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE || 178 download_item->GetDangerType() == 179 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL || 180 download_item->GetDangerType() == 181 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT || 182 download_item->GetDangerType() == 183 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT || 184 download_item->GetDangerType() == 185 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST || 186 download_item->GetDangerType() == 187 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED); 188 const char* danger_type_value = 189 GetDangerTypeString(download_item->GetDangerType()); 190 file_value->SetString("danger_type", danger_type_value); 191 } else if (download_item->IsPaused()) { 192 file_value->SetString("state", "PAUSED"); 193 } else { 194 file_value->SetString("state", "IN_PROGRESS"); 195 } 196 file_value->SetString("progress_status_text", 197 download_model.GetTabProgressStatusText()); 198 199 file_value->SetInteger("percent", 200 static_cast<int>(download_item->PercentComplete())); 201 file_value->SetInteger("received", 202 static_cast<int>(download_item->GetReceivedBytes())); 203 break; 204 205 case content::DownloadItem::INTERRUPTED: 206 file_value->SetString("state", "INTERRUPTED"); 207 208 file_value->SetString("progress_status_text", 209 download_model.GetTabProgressStatusText()); 210 211 file_value->SetInteger("percent", 212 static_cast<int>(download_item->PercentComplete())); 213 file_value->SetInteger("received", 214 static_cast<int>(download_item->GetReceivedBytes())); 215 file_value->SetString("last_reason_text", 216 download_model.GetInterruptReasonText()); 217 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH == 218 download_item->GetLastReason() && !download_item->CanResume()) 219 file_value->SetBoolean("retry", true); 220 break; 221 222 case content::DownloadItem::CANCELLED: 223 file_value->SetString("state", "CANCELLED"); 224 file_value->SetBoolean("retry", true); 225 break; 226 227 case content::DownloadItem::COMPLETE: 228 DCHECK(!download_item->IsDangerous()); 229 file_value->SetString("state", "COMPLETE"); 230 break; 231 232 case content::DownloadItem::MAX_DOWNLOAD_STATE: 233 NOTREACHED() << "state undefined"; 234 } 235 236 return file_value; 237 } 238 239 // Filters out extension downloads and downloads that don't have a filename yet. 240 bool IsDownloadDisplayable(const content::DownloadItem& item) { 241 return (!download_crx_util::IsExtensionDownload(item) && 242 !item.IsTemporary() && 243 !item.GetFileNameToReportUser().empty() && 244 !item.GetTargetFilePath().empty()); 245 } 246 247 } // namespace 248 249 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm) 250 : main_notifier_(dlm, this), 251 update_scheduled_(false), 252 weak_ptr_factory_(this) { 253 // Create our fileicon data source. 254 Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext()); 255 content::URLDataSource::Add(profile, new FileIconSource()); 256 257 if (profile->IsOffTheRecord()) { 258 original_notifier_.reset(new AllDownloadItemNotifier( 259 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()), 260 this)); 261 } 262 } 263 264 DownloadsDOMHandler::~DownloadsDOMHandler() { 265 } 266 267 // DownloadsDOMHandler, public: ----------------------------------------------- 268 269 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue* args) { 270 SendCurrentDownloads(); 271 } 272 273 void DownloadsDOMHandler::RegisterMessages() { 274 web_ui()->RegisterMessageCallback("onPageLoaded", 275 base::Bind(&DownloadsDOMHandler::OnPageLoaded, 276 weak_ptr_factory_.GetWeakPtr())); 277 web_ui()->RegisterMessageCallback("getDownloads", 278 base::Bind(&DownloadsDOMHandler::HandleGetDownloads, 279 weak_ptr_factory_.GetWeakPtr())); 280 web_ui()->RegisterMessageCallback("openFile", 281 base::Bind(&DownloadsDOMHandler::HandleOpenFile, 282 weak_ptr_factory_.GetWeakPtr())); 283 web_ui()->RegisterMessageCallback("drag", 284 base::Bind(&DownloadsDOMHandler::HandleDrag, 285 weak_ptr_factory_.GetWeakPtr())); 286 web_ui()->RegisterMessageCallback("saveDangerous", 287 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous, 288 weak_ptr_factory_.GetWeakPtr())); 289 web_ui()->RegisterMessageCallback("discardDangerous", 290 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous, 291 weak_ptr_factory_.GetWeakPtr())); 292 web_ui()->RegisterMessageCallback("show", 293 base::Bind(&DownloadsDOMHandler::HandleShow, 294 weak_ptr_factory_.GetWeakPtr())); 295 web_ui()->RegisterMessageCallback("pause", 296 base::Bind(&DownloadsDOMHandler::HandlePause, 297 weak_ptr_factory_.GetWeakPtr())); 298 web_ui()->RegisterMessageCallback("resume", 299 base::Bind(&DownloadsDOMHandler::HandleResume, 300 weak_ptr_factory_.GetWeakPtr())); 301 web_ui()->RegisterMessageCallback("remove", 302 base::Bind(&DownloadsDOMHandler::HandleRemove, 303 weak_ptr_factory_.GetWeakPtr())); 304 web_ui()->RegisterMessageCallback("cancel", 305 base::Bind(&DownloadsDOMHandler::HandleCancel, 306 weak_ptr_factory_.GetWeakPtr())); 307 web_ui()->RegisterMessageCallback("clearAll", 308 base::Bind(&DownloadsDOMHandler::HandleClearAll, 309 weak_ptr_factory_.GetWeakPtr())); 310 web_ui()->RegisterMessageCallback("openDownloadsFolder", 311 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder, 312 weak_ptr_factory_.GetWeakPtr())); 313 } 314 315 void DownloadsDOMHandler::OnDownloadCreated( 316 content::DownloadManager* manager, content::DownloadItem* download_item) { 317 if (IsDownloadDisplayable(*download_item)) 318 ScheduleSendCurrentDownloads(); 319 } 320 321 void DownloadsDOMHandler::OnDownloadUpdated( 322 content::DownloadManager* manager, 323 content::DownloadItem* download_item) { 324 if (IsDownloadDisplayable(*download_item)) { 325 if (search_terms_ && !search_terms_->empty()) { 326 // Don't CallDownloadUpdated() if download_item doesn't match 327 // search_terms_. 328 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function. 329 content::DownloadManager::DownloadVector all_items, filtered_items; 330 all_items.push_back(download_item); 331 DownloadQuery query; 332 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get()); 333 query.Search(all_items.begin(), all_items.end(), &filtered_items); 334 if (filtered_items.empty()) 335 return; 336 } 337 base::ListValue results_value; 338 results_value.Append(CreateDownloadItemValue( 339 download_item, 340 (original_notifier_.get() && 341 (manager == main_notifier_.GetManager())))); 342 CallDownloadUpdated(results_value); 343 } 344 } 345 346 void DownloadsDOMHandler::OnDownloadRemoved( 347 content::DownloadManager* manager, 348 content::DownloadItem* download_item) { 349 // This relies on |download_item| being removed from DownloadManager in this 350 // MessageLoop iteration. |download_item| may not have been removed from 351 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the 352 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks 353 // at all downloads, and we do not tell it that |download_item| is being 354 // removed. If DownloadManager is ever changed to not immediately remove 355 // |download_item| from its map when OnDownloadRemoved is sent, then 356 // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell 357 // SendCurrentDownloads() that |download_item| was removed. A 358 // SupportsUserData::Data would be the correct way to do this. 359 ScheduleSendCurrentDownloads(); 360 } 361 362 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) { 363 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); 364 search_terms_.reset((args && !args->empty()) ? args->DeepCopy() : NULL); 365 SendCurrentDownloads(); 366 } 367 368 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) { 369 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE); 370 content::DownloadItem* file = GetDownloadByValue(args); 371 if (file) 372 file->OpenDownload(); 373 } 374 375 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) { 376 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG); 377 content::DownloadItem* file = GetDownloadByValue(args); 378 if (!file) 379 return; 380 381 content::WebContents* web_contents = GetWebUIWebContents(); 382 // |web_contents| is only NULL in the test. 383 if (!web_contents) 384 return; 385 386 if (file->GetState() != content::DownloadItem::COMPLETE) 387 return; 388 389 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath( 390 file->GetTargetFilePath(), IconLoader::NORMAL); 391 gfx::NativeView view = web_contents->GetNativeView(); 392 { 393 // Enable nested tasks during DnD, while |DragDownload()| blocks. 394 base::MessageLoop::ScopedNestableTaskAllower allow( 395 base::MessageLoop::current()); 396 DragDownloadItem(file, icon, view); 397 } 398 } 399 400 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) { 401 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS); 402 content::DownloadItem* file = GetDownloadByValue(args); 403 if (file) 404 ShowDangerPrompt(file); 405 } 406 407 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) { 408 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS); 409 content::DownloadItem* file = GetDownloadByValue(args); 410 if (file) 411 file->Remove(); 412 } 413 414 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) { 415 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW); 416 content::DownloadItem* file = GetDownloadByValue(args); 417 if (file) 418 file->ShowDownloadInShell(); 419 } 420 421 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) { 422 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE); 423 content::DownloadItem* file = GetDownloadByValue(args); 424 if (file) 425 file->Pause(); 426 } 427 428 void DownloadsDOMHandler::HandleResume(const base::ListValue* args) { 429 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME); 430 content::DownloadItem* file = GetDownloadByValue(args); 431 if (file) 432 file->Resume(); 433 } 434 435 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) { 436 if (!IsDeletingHistoryAllowed()) 437 return; 438 439 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE); 440 content::DownloadItem* file = GetDownloadByValue(args); 441 if (file) 442 file->Remove(); 443 } 444 445 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) { 446 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL); 447 content::DownloadItem* file = GetDownloadByValue(args); 448 if (file) 449 file->Cancel(true); 450 } 451 452 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) { 453 if (IsDeletingHistoryAllowed()) { 454 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); 455 // IsDeletingHistoryAllowed already checked for the existence of the 456 // manager. 457 main_notifier_.GetManager()->RemoveAllDownloads(); 458 459 // If this is an incognito downloads page, clear All should clear main 460 // download manager as well. 461 if (original_notifier_.get() && original_notifier_->GetManager()) 462 original_notifier_->GetManager()->RemoveAllDownloads(); 463 } 464 465 // downloads.js always clears the display and relies on HandleClearAll to 466 // ScheduleSendCurrentDownloads(). If any downloads are removed, then 467 // OnDownloadRemoved() will call it, but if no downloads are actually removed, 468 // then HandleClearAll needs to call it manually. 469 ScheduleSendCurrentDownloads(); 470 } 471 472 void DownloadsDOMHandler::HandleOpenDownloadsFolder( 473 const base::ListValue* args) { 474 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER); 475 content::DownloadManager* manager = main_notifier_.GetManager(); 476 if (manager) { 477 platform_util::OpenItem( 478 Profile::FromBrowserContext(manager->GetBrowserContext()), 479 DownloadPrefs::FromDownloadManager(manager)->DownloadPath()); 480 } 481 } 482 483 // DownloadsDOMHandler, private: ---------------------------------------------- 484 485 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() { 486 // Don't call SendCurrentDownloads() every time anything changes. Batch them 487 // together instead. This may handle hundreds of OnDownloadDestroyed() calls 488 // in a single UI message loop iteration when the user Clears All downloads. 489 if (update_scheduled_) 490 return; 491 update_scheduled_ = true; 492 BrowserThread::PostTask( 493 BrowserThread::UI, FROM_HERE, 494 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads, 495 weak_ptr_factory_.GetWeakPtr())); 496 } 497 498 void DownloadsDOMHandler::SendCurrentDownloads() { 499 update_scheduled_ = false; 500 content::DownloadManager::DownloadVector all_items, filtered_items; 501 if (main_notifier_.GetManager()) { 502 main_notifier_.GetManager()->GetAllDownloads(&all_items); 503 main_notifier_.GetManager()->CheckForHistoryFilesRemoval(); 504 } 505 if (original_notifier_.get() && original_notifier_->GetManager()) { 506 original_notifier_->GetManager()->GetAllDownloads(&all_items); 507 original_notifier_->GetManager()->CheckForHistoryFilesRemoval(); 508 } 509 DownloadQuery query; 510 if (search_terms_ && !search_terms_->empty()) { 511 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get()); 512 } 513 query.AddFilter(base::Bind(&IsDownloadDisplayable)); 514 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING); 515 query.Limit(kMaxDownloads); 516 query.Search(all_items.begin(), all_items.end(), &filtered_items); 517 base::ListValue results_value; 518 for (content::DownloadManager::DownloadVector::const_iterator 519 iter = filtered_items.begin(); iter != filtered_items.end(); ++iter) { 520 results_value.Append(CreateDownloadItemValue( 521 *iter, 522 (original_notifier_.get() && 523 main_notifier_.GetManager() && 524 (main_notifier_.GetManager()->GetDownload((*iter)->GetId()) == 525 *iter)))); 526 } 527 CallDownloadsList(results_value); 528 } 529 530 void DownloadsDOMHandler::ShowDangerPrompt( 531 content::DownloadItem* dangerous_item) { 532 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( 533 dangerous_item, 534 GetWebUIWebContents(), 535 false, 536 base::Bind(&DownloadsDOMHandler::DangerPromptDone, 537 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId())); 538 // danger_prompt will delete itself. 539 DCHECK(danger_prompt); 540 } 541 542 void DownloadsDOMHandler::DangerPromptDone( 543 int download_id, DownloadDangerPrompt::Action action) { 544 if (action != DownloadDangerPrompt::ACCEPT) 545 return; 546 content::DownloadItem* item = NULL; 547 if (main_notifier_.GetManager()) 548 item = main_notifier_.GetManager()->GetDownload(download_id); 549 if (!item && original_notifier_.get() && original_notifier_->GetManager()) 550 item = original_notifier_->GetManager()->GetDownload(download_id); 551 if (!item || item->IsDone()) 552 return; 553 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS); 554 item->ValidateDangerousDownload(); 555 } 556 557 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() { 558 content::DownloadManager* manager = main_notifier_.GetManager(); 559 return (manager && 560 Profile::FromBrowserContext(manager->GetBrowserContext())-> 561 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory)); 562 } 563 564 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue( 565 const base::ListValue* args) { 566 int download_id = -1; 567 if (!ExtractIntegerValue(args, &download_id)) 568 return NULL; 569 content::DownloadItem* item = NULL; 570 if (main_notifier_.GetManager()) 571 item = main_notifier_.GetManager()->GetDownload(download_id); 572 if (!item && original_notifier_.get() && original_notifier_->GetManager()) 573 item = original_notifier_->GetManager()->GetDownload(download_id); 574 return item; 575 } 576 577 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() { 578 return web_ui()->GetWebContents(); 579 } 580 581 void DownloadsDOMHandler::CallDownloadsList(const base::ListValue& downloads) { 582 web_ui()->CallJavascriptFunction("downloadsList", downloads); 583 } 584 585 void DownloadsDOMHandler::CallDownloadUpdated( 586 const base::ListValue& download_item) { 587 web_ui()->CallJavascriptFunction("downloadUpdated", download_item); 588 } 589