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