download_util.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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// Download utility implementation 6 7#include "chrome/browser/download/download_util.h" 8 9#if defined(OS_WIN) 10#include <shobjidl.h> 11#endif 12#include <string> 13 14#include "app/l10n_util.h" 15#include "app/resource_bundle.h" 16#include "base/file_util.h" 17#include "base/i18n/rtl.h" 18#include "base/i18n/time_formatting.h" 19#include "base/path_service.h" 20#include "base/singleton.h" 21#include "base/string16.h" 22#include "base/string_number_conversions.h" 23#include "base/stringprintf.h" 24#include "base/sys_string_conversions.h" 25#include "base/thread_restrictions.h" 26#include "base/utf_string_conversions.h" 27#include "base/values.h" 28#include "base/win/windows_version.h" 29#include "chrome/browser/browser.h" 30#include "chrome/browser/browser_list.h" 31#include "chrome/browser/browser_process.h" 32#include "chrome/browser/browser_thread.h" 33#include "chrome/browser/download/download_item.h" 34#include "chrome/browser/download/download_item_model.h" 35#include "chrome/browser/download/download_manager.h" 36#include "chrome/browser/extensions/crx_installer.h" 37#include "chrome/browser/extensions/extension_install_ui.h" 38#include "chrome/browser/extensions/extensions_service.h" 39#include "chrome/browser/history/download_create_info.h" 40#include "chrome/browser/net/chrome_url_request_context.h" 41#include "chrome/browser/profile.h" 42#include "chrome/browser/renderer_host/resource_dispatcher_host.h" 43#include "chrome/browser/tab_contents/infobar_delegate.h" 44#include "chrome/browser/tab_contents/tab_contents.h" 45#include "chrome/common/chrome_paths.h" 46#include "chrome/common/notification_service.h" 47#include "chrome/common/time_format.h" 48#include "gfx/canvas_skia.h" 49#include "gfx/rect.h" 50#include "grit/generated_resources.h" 51#include "grit/locale_settings.h" 52#include "grit/theme_resources.h" 53#include "net/base/mime_util.h" 54#include "net/base/net_util.h" 55#include "skia/ext/image_operations.h" 56#include "third_party/skia/include/core/SkPath.h" 57#include "third_party/skia/include/core/SkShader.h" 58 59#if defined(TOOLKIT_VIEWS) 60#include "app/os_exchange_data.h" 61#include "views/drag_utils.h" 62#endif 63 64#if defined(TOOLKIT_USES_GTK) 65#if defined(TOOLKIT_VIEWS) 66#include "app/drag_drop_types.h" 67#include "views/widget/widget_gtk.h" 68#elif defined(TOOLKIT_GTK) 69#include "chrome/browser/gtk/custom_drag.h" 70#endif // defined(TOOLKIT_GTK) 71#endif // defined(TOOLKIT_USES_GTK) 72 73#if defined(OS_WIN) 74#include "app/os_exchange_data_provider_win.h" 75#include "app/win_util.h" 76#include "app/win/drag_source.h" 77#include "base/win/scoped_comptr.h" 78#include "base/win_util.h" 79#include "chrome/browser/browser_list.h" 80#include "chrome/browser/views/frame/browser_view.h" 81#endif 82 83namespace download_util { 84 85// How many times to cycle the complete animation. This should be an odd number 86// so that the animation ends faded out. 87static const int kCompleteAnimationCycles = 5; 88 89// Download temporary file creation -------------------------------------------- 90 91class DefaultDownloadDirectory { 92 public: 93 const FilePath& path() const { return path_; } 94 private: 95 DefaultDownloadDirectory() { 96 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path_)) { 97 NOTREACHED(); 98 } 99 if (DownloadPathIsDangerous(path_)) { 100 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &path_)) { 101 NOTREACHED(); 102 } 103 } 104 } 105 friend struct DefaultSingletonTraits<DefaultDownloadDirectory>; 106 FilePath path_; 107}; 108 109const FilePath& GetDefaultDownloadDirectory() { 110 return Singleton<DefaultDownloadDirectory>::get()->path(); 111} 112 113bool CreateTemporaryFileForDownload(FilePath* temp_file) { 114 if (file_util::CreateTemporaryFileInDir(GetDefaultDownloadDirectory(), 115 temp_file)) 116 return true; 117 return file_util::CreateTemporaryFile(temp_file); 118} 119 120bool DownloadPathIsDangerous(const FilePath& download_path) { 121 FilePath desktop_dir; 122 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_dir)) { 123 NOTREACHED(); 124 return false; 125 } 126 return (download_path == desktop_dir); 127} 128 129void GenerateExtension(const FilePath& file_name, 130 const std::string& mime_type, 131 FilePath::StringType* generated_extension) { 132 // We're worried about two things here: 133 // 134 // 1) Usability. If the site fails to provide a file extension, we want to 135 // guess a reasonable file extension based on the content type. 136 // 137 // 2) Shell integration. Some file extensions automatically integrate with 138 // the shell. We block these extensions to prevent a malicious web site 139 // from integrating with the user's shell. 140 141 // See if our file name already contains an extension. 142 FilePath::StringType extension = file_name.Extension(); 143 if (!extension.empty()) 144 extension.erase(extension.begin()); // Erase preceding '.'. 145 146#if defined(OS_WIN) 147 static const FilePath::CharType default_extension[] = 148 FILE_PATH_LITERAL("download"); 149 150 // Rename shell-integrated extensions. 151 if (win_util::IsShellIntegratedExtension(extension)) 152 extension.assign(default_extension); 153#endif 154 155 if (extension.empty()) { 156 // The GetPreferredExtensionForMimeType call will end up going to disk. Do 157 // this on another thread to avoid slowing the IO thread. 158 // http://crbug.com/61827 159 base::ThreadRestrictions::ScopedAllowIO allow_io; 160 net::GetPreferredExtensionForMimeType(mime_type, &extension); 161 } 162 163 generated_extension->swap(extension); 164} 165 166void GenerateFileNameFromInfo(DownloadCreateInfo* info, 167 FilePath* generated_name) { 168 GenerateFileName(GURL(info->url), 169 info->content_disposition, 170 info->referrer_charset, 171 info->mime_type, 172 generated_name); 173} 174 175void GenerateFileName(const GURL& url, 176 const std::string& content_disposition, 177 const std::string& referrer_charset, 178 const std::string& mime_type, 179 FilePath* generated_name) { 180 std::wstring default_name = 181 l10n_util::GetString(IDS_DEFAULT_DOWNLOAD_FILENAME); 182#if defined(OS_WIN) 183 FilePath default_file_path(default_name); 184#elif defined(OS_POSIX) 185 FilePath default_file_path(base::SysWideToNativeMB(default_name)); 186#endif 187 188 *generated_name = net::GetSuggestedFilename(GURL(url), 189 content_disposition, 190 referrer_charset, 191 default_file_path); 192 193 DCHECK(!generated_name->empty()); 194 195 GenerateSafeFileName(mime_type, generated_name); 196} 197 198void GenerateSafeFileName(const std::string& mime_type, FilePath* file_name) { 199 // Make sure we get the right file extension 200 FilePath::StringType extension; 201 GenerateExtension(*file_name, mime_type, &extension); 202 *file_name = file_name->ReplaceExtension(extension); 203 204#if defined(OS_WIN) 205 // Prepend "_" to the file name if it's a reserved name 206 FilePath::StringType leaf_name = file_name->BaseName().value(); 207 DCHECK(!leaf_name.empty()); 208 if (win_util::IsReservedName(leaf_name)) { 209 leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name; 210 *file_name = file_name->DirName(); 211 if (file_name->value() == FilePath::kCurrentDirectory) { 212 *file_name = FilePath(leaf_name); 213 } else { 214 *file_name = file_name->Append(leaf_name); 215 } 216 } 217#endif 218} 219 220void OpenChromeExtension(Profile* profile, 221 DownloadManager* download_manager, 222 const DownloadItem& download_item) { 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 224 DCHECK(download_item.is_extension_install()); 225 226 // We don't support extensions in OTR mode. 227 ExtensionsService* service = profile->GetExtensionsService(); 228 if (service) { 229 NotificationService* nservice = NotificationService::current(); 230 GURL nonconst_download_url = download_item.url(); 231 nservice->Notify(NotificationType::EXTENSION_READY_FOR_INSTALL, 232 Source<DownloadManager>(download_manager), 233 Details<GURL>(&nonconst_download_url)); 234 235 scoped_refptr<CrxInstaller> installer( 236 new CrxInstaller(service->install_directory(), 237 service, 238 new ExtensionInstallUI(profile))); 239 installer->set_delete_source(true); 240 241 if (UserScript::HasUserScriptFileExtension(download_item.url())) { 242 installer->InstallUserScript(download_item.full_path(), 243 download_item.url()); 244 } else { 245 bool is_gallery_download = service->IsDownloadFromGallery( 246 download_item.url(), download_item.referrer_url()); 247 installer->set_original_mime_type(download_item.original_mime_type()); 248 installer->set_apps_require_extension_mime_type(true); 249 installer->set_allow_privilege_increase(true); 250 installer->set_original_url(download_item.url()); 251 installer->set_is_gallery_install(is_gallery_download); 252 installer->InstallCrx(download_item.full_path()); 253 installer->set_allow_silent_install(is_gallery_download); 254 } 255 } else { 256 TabContents* contents = NULL; 257 // Get last active normal browser of profile. 258 Browser* last_active = 259 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, true); 260 if (last_active) 261 contents = last_active->GetSelectedTabContents(); 262 if (contents) { 263 contents->AddInfoBar( 264 new SimpleAlertInfoBarDelegate(contents, 265 l10n_util::GetStringUTF16( 266 IDS_EXTENSION_INCOGNITO_INSTALL_INFOBAR_LABEL), 267 ResourceBundle::GetSharedInstance().GetBitmapNamed( 268 IDR_INFOBAR_PLUGIN_INSTALL), 269 true)); 270 } 271 } 272} 273 274// Download progress painting -------------------------------------------------- 275 276// Common bitmaps used for download progress animations. We load them once the 277// first time we do a progress paint, then reuse them as they are always the 278// same. 279SkBitmap* g_foreground_16 = NULL; 280SkBitmap* g_background_16 = NULL; 281SkBitmap* g_foreground_32 = NULL; 282SkBitmap* g_background_32 = NULL; 283 284void PaintDownloadProgress(gfx::Canvas* canvas, 285#if defined(TOOLKIT_VIEWS) 286 views::View* containing_view, 287#endif 288 int origin_x, 289 int origin_y, 290 int start_angle, 291 int percent_done, 292 PaintDownloadProgressSize size) { 293 // Load up our common bitmaps 294 if (!g_background_16) { 295 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 296 g_foreground_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16); 297 g_background_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_16); 298 g_foreground_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32); 299 g_background_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_32); 300 } 301 302 SkBitmap* background = (size == BIG) ? g_background_32 : g_background_16; 303 SkBitmap* foreground = (size == BIG) ? g_foreground_32 : g_foreground_16; 304 305 const int kProgressIconSize = (size == BIG) ? kBigProgressIconSize : 306 kSmallProgressIconSize; 307 308 // We start by storing the bounds of the background and foreground bitmaps 309 // so that it is easy to mirror the bounds if the UI layout is RTL. 310 gfx::Rect background_bounds(origin_x, origin_y, 311 background->width(), background->height()); 312 gfx::Rect foreground_bounds(origin_x, origin_y, 313 foreground->width(), foreground->height()); 314 315#if defined(TOOLKIT_VIEWS) 316 // Mirror the positions if necessary. 317 int mirrored_x = containing_view->MirroredLeftPointForRect(background_bounds); 318 background_bounds.set_x(mirrored_x); 319 mirrored_x = containing_view->MirroredLeftPointForRect(foreground_bounds); 320 foreground_bounds.set_x(mirrored_x); 321#endif 322 323 // Draw the background progress image. 324 SkPaint background_paint; 325 canvas->DrawBitmapInt(*background, 326 background_bounds.x(), 327 background_bounds.y(), 328 background_paint); 329 330 // Layer the foreground progress image in an arc proportional to the download 331 // progress. The arc grows clockwise, starting in the midnight position, as 332 // the download progresses. However, if the download does not have known total 333 // size (the server didn't give us one), then we just spin an arc around until 334 // we're done. 335 float sweep_angle = 0.0; 336 float start_pos = static_cast<float>(kStartAngleDegrees); 337 if (percent_done < 0) { 338 sweep_angle = kUnknownAngleDegrees; 339 start_pos = static_cast<float>(start_angle); 340 } else if (percent_done > 0) { 341 sweep_angle = static_cast<float>(kMaxDegrees / 100.0 * percent_done); 342 } 343 344 // Set up an arc clipping region for the foreground image. Don't bother using 345 // a clipping region if it would round to 360 (really 0) degrees, since that 346 // would eliminate the foreground completely and be quite confusing (it would 347 // look like 0% complete when it should be almost 100%). 348 SkPaint foreground_paint; 349 if (sweep_angle < static_cast<float>(kMaxDegrees - 1)) { 350 SkRect oval; 351 oval.set(SkIntToScalar(foreground_bounds.x()), 352 SkIntToScalar(foreground_bounds.y()), 353 SkIntToScalar(foreground_bounds.x() + kProgressIconSize), 354 SkIntToScalar(foreground_bounds.y() + kProgressIconSize)); 355 SkPath path; 356 path.arcTo(oval, 357 SkFloatToScalar(start_pos), 358 SkFloatToScalar(sweep_angle), false); 359 path.lineTo(SkIntToScalar(foreground_bounds.x() + kProgressIconSize / 2), 360 SkIntToScalar(foreground_bounds.y() + kProgressIconSize / 2)); 361 362 SkShader* shader = 363 SkShader::CreateBitmapShader(*foreground, 364 SkShader::kClamp_TileMode, 365 SkShader::kClamp_TileMode); 366 SkMatrix shader_scale; 367 shader_scale.setTranslate(SkIntToScalar(foreground_bounds.x()), 368 SkIntToScalar(foreground_bounds.y())); 369 shader->setLocalMatrix(shader_scale); 370 foreground_paint.setShader(shader); 371 foreground_paint.setAntiAlias(true); 372 shader->unref(); 373 canvas->AsCanvasSkia()->drawPath(path, foreground_paint); 374 return; 375 } 376 377 canvas->DrawBitmapInt(*foreground, 378 foreground_bounds.x(), 379 foreground_bounds.y(), 380 foreground_paint); 381} 382 383void PaintDownloadComplete(gfx::Canvas* canvas, 384#if defined(TOOLKIT_VIEWS) 385 views::View* containing_view, 386#endif 387 int origin_x, 388 int origin_y, 389 double animation_progress, 390 PaintDownloadProgressSize size) { 391 // Load up our common bitmaps. 392 if (!g_foreground_16) { 393 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 394 g_foreground_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16); 395 g_foreground_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32); 396 } 397 398 SkBitmap* complete = (size == BIG) ? g_foreground_32 : g_foreground_16; 399 400 gfx::Rect complete_bounds(origin_x, origin_y, 401 complete->width(), complete->height()); 402#if defined(TOOLKIT_VIEWS) 403 // Mirror the positions if necessary. 404 complete_bounds.set_x( 405 containing_view->MirroredLeftPointForRect(complete_bounds)); 406#endif 407 408 // Start at full opacity, then loop back and forth five times before ending 409 // at zero opacity. 410 static const double PI = 3.141592653589793; 411 double opacity = sin(animation_progress * PI * kCompleteAnimationCycles + 412 PI/2) / 2 + 0.5; 413 414 canvas->SaveLayerAlpha(static_cast<int>(255.0 * opacity), complete_bounds); 415 canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); 416 canvas->DrawBitmapInt(*complete, complete_bounds.x(), complete_bounds.y()); 417 canvas->Restore(); 418} 419 420// Load a language dependent height so that the dangerous download confirmation 421// message doesn't overlap with the download link label. 422int GetBigProgressIconSize() { 423 static int big_progress_icon_size = 0; 424 if (big_progress_icon_size == 0) { 425 string16 locale_size_str = 426 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BIG_PROGRESS_SIZE); 427 bool rc = base::StringToInt(locale_size_str, &big_progress_icon_size); 428 if (!rc || big_progress_icon_size < kBigProgressIconSize) { 429 NOTREACHED(); 430 big_progress_icon_size = kBigProgressIconSize; 431 } 432 } 433 434 return big_progress_icon_size; 435} 436 437int GetBigProgressIconOffset() { 438 return (GetBigProgressIconSize() - kBigIconSize) / 2; 439} 440 441#if defined(TOOLKIT_VIEWS) 442// Download dragging 443void DragDownload(const DownloadItem* download, 444 SkBitmap* icon, 445 gfx::NativeView view) { 446 DCHECK(download); 447 448 // Set up our OLE machinery 449 OSExchangeData data; 450 451 if (icon) { 452 drag_utils::CreateDragImageForFile( 453 download->GetFileNameToReportUser().value(), icon, &data); 454 } 455 456 const FilePath full_path = download->full_path(); 457 data.SetFilename(full_path.ToWStringHack()); 458 459 std::string mime_type = download->mime_type(); 460 if (mime_type.empty()) 461 net::GetMimeTypeFromFile(full_path, &mime_type); 462 463 // Add URL so that we can load supported files when dragged to TabContents. 464 if (net::IsSupportedMimeType(mime_type)) { 465 data.SetURL(GURL(WideToUTF8(full_path.ToWStringHack())), 466 download->GetFileNameToReportUser().ToWStringHack()); 467 } 468 469#if defined(OS_WIN) 470 scoped_refptr<app::win::DragSource> drag_source(new app::win::DragSource); 471 472 // Run the drag and drop loop 473 DWORD effects; 474 DoDragDrop(OSExchangeDataProviderWin::GetIDataObject(data), drag_source.get(), 475 DROPEFFECT_COPY | DROPEFFECT_LINK, &effects); 476#elif defined(TOOLKIT_USES_GTK) 477 GtkWidget* root = gtk_widget_get_toplevel(view); 478 if (!root) 479 return; 480 views::WidgetGtk* widget = views::WidgetGtk::GetViewForNative(root); 481 if (!widget) 482 return; 483 484 widget->DoDrag(data, DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK); 485#endif // OS_WIN 486} 487#elif defined(USE_X11) 488void DragDownload(const DownloadItem* download, 489 SkBitmap* icon, 490 gfx::NativeView view) { 491 DownloadItemDrag::BeginDrag(download, icon); 492} 493#endif // USE_X11 494 495DictionaryValue* CreateDownloadItemValue(DownloadItem* download, int id) { 496 DictionaryValue* file_value = new DictionaryValue(); 497 498 file_value->SetInteger("started", 499 static_cast<int>(download->start_time().ToTimeT())); 500 file_value->SetString("since_string", 501 TimeFormat::RelativeDate(download->start_time(), NULL)); 502 file_value->SetString("date_string", 503 WideToUTF16Hack(base::TimeFormatShortDate(download->start_time()))); 504 file_value->SetInteger("id", id); 505 file_value->SetString("file_path", 506 WideToUTF16Hack(download->GetTargetFilePath().ToWStringHack())); 507 // Keep file names as LTR. 508 string16 file_name = WideToUTF16Hack( 509 download->GetFileNameToReportUser().ToWStringHack()); 510 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); 511 file_value->SetString("file_name", file_name); 512 file_value->SetString("url", download->url().spec()); 513 file_value->SetBoolean("otr", download->is_otr()); 514 515 if (download->state() == DownloadItem::IN_PROGRESS) { 516 if (download->safety_state() == DownloadItem::DANGEROUS) { 517 file_value->SetString("state", "DANGEROUS"); 518 } else if (download->is_paused()) { 519 file_value->SetString("state", "PAUSED"); 520 } else { 521 file_value->SetString("state", "IN_PROGRESS"); 522 } 523 524 file_value->SetString("progress_status_text", 525 WideToUTF16Hack(GetProgressStatusText(download))); 526 527 file_value->SetInteger("percent", 528 static_cast<int>(download->PercentComplete())); 529 file_value->SetInteger("received", 530 static_cast<int>(download->received_bytes())); 531 } else if (download->state() == DownloadItem::CANCELLED) { 532 file_value->SetString("state", "CANCELLED"); 533 } else if (download->state() == DownloadItem::COMPLETE) { 534 if (download->safety_state() == DownloadItem::DANGEROUS) { 535 file_value->SetString("state", "DANGEROUS"); 536 } else { 537 file_value->SetString("state", "COMPLETE"); 538 } 539 } 540 541 file_value->SetInteger("total", 542 static_cast<int>(download->total_bytes())); 543 544 return file_value; 545} 546 547std::wstring GetProgressStatusText(DownloadItem* download) { 548 int64 total = download->total_bytes(); 549 int64 size = download->received_bytes(); 550 DataUnits amount_units = GetByteDisplayUnits(size); 551 std::wstring received_size = UTF16ToWideHack(FormatBytes(size, amount_units, 552 true)); 553 std::wstring amount = received_size; 554 555 // Adjust both strings for the locale direction since we don't yet know which 556 // string we'll end up using for constructing the final progress string. 557 std::wstring amount_localized; 558 if (base::i18n::AdjustStringForLocaleDirection(amount, &amount_localized)) { 559 amount.assign(amount_localized); 560 received_size.assign(amount_localized); 561 } 562 563 if (total) { 564 amount_units = GetByteDisplayUnits(total); 565 std::wstring total_text = 566 UTF16ToWideHack(FormatBytes(total, amount_units, true)); 567 std::wstring total_text_localized; 568 if (base::i18n::AdjustStringForLocaleDirection(total_text, 569 &total_text_localized)) 570 total_text.assign(total_text_localized); 571 572 amount = l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_SIZE, 573 received_size, 574 total_text); 575 } else { 576 amount.assign(received_size); 577 } 578 amount_units = GetByteDisplayUnits(download->CurrentSpeed()); 579 std::wstring speed_text = 580 UTF16ToWideHack(FormatSpeed(download->CurrentSpeed(), amount_units, 581 true)); 582 std::wstring speed_text_localized; 583 if (base::i18n::AdjustStringForLocaleDirection(speed_text, 584 &speed_text_localized)) 585 speed_text.assign(speed_text_localized); 586 587 base::TimeDelta remaining; 588 string16 time_remaining; 589 if (download->is_paused()) 590 time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED); 591 else if (download->TimeRemaining(&remaining)) 592 time_remaining = TimeFormat::TimeRemaining(remaining); 593 594 if (time_remaining.empty()) { 595 return l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, 596 speed_text, amount); 597 } 598 return l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, 599 amount, UTF16ToWideHack(time_remaining)); 600} 601 602#if !defined(OS_MACOSX) 603void UpdateAppIconDownloadProgress(int download_count, 604 bool progress_known, 605 float progress) { 606#if defined(OS_WIN) 607 // Taskbar progress bar is only supported on Win7. 608 if (base::win::GetVersion() < base::win::VERSION_WIN7) 609 return; 610 611 base::win::ScopedComPtr<ITaskbarList3> taskbar; 612 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, 613 CLSCTX_INPROC_SERVER); 614 if (FAILED(result)) { 615 VLOG(1) << "Failed creating a TaskbarList object: " << result; 616 return; 617 } 618 619 result = taskbar->HrInit(); 620 if (FAILED(result)) { 621 LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; 622 return; 623 } 624 625 // Iterate through all the browser windows, and draw the progress bar. 626 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); 627 browser_iterator != BrowserList::end(); browser_iterator++) { 628 HWND frame = (*browser_iterator)->window()->GetNativeHandle(); 629 if (download_count == 0 || progress == 1.0f) 630 taskbar->SetProgressState(frame, TBPF_NOPROGRESS); 631 else if (!progress_known) 632 taskbar->SetProgressState(frame, TBPF_INDETERMINATE); 633 else 634 taskbar->SetProgressValue(frame, (int)(progress * 100), 100); 635 } 636#endif 637} 638#endif 639 640// Appends the passed the number between parenthesis the path before the 641// extension. 642void AppendNumberToPath(FilePath* path, int number) { 643 *path = path->InsertBeforeExtensionASCII(StringPrintf(" (%d)", number)); 644} 645 646// Attempts to find a number that can be appended to that path to make it 647// unique. If |path| does not exist, 0 is returned. If it fails to find such 648// a number, -1 is returned. 649int GetUniquePathNumber(const FilePath& path) { 650 const int kMaxAttempts = 100; 651 652 if (!file_util::PathExists(path)) 653 return 0; 654 655 FilePath new_path; 656 for (int count = 1; count <= kMaxAttempts; ++count) { 657 new_path = FilePath(path); 658 AppendNumberToPath(&new_path, count); 659 660 if (!file_util::PathExists(new_path)) 661 return count; 662 } 663 664 return -1; 665} 666 667void DownloadUrl( 668 const GURL& url, 669 const GURL& referrer, 670 const std::string& referrer_charset, 671 const DownloadSaveInfo& save_info, 672 ResourceDispatcherHost* rdh, 673 int render_process_host_id, 674 int render_view_id, 675 URLRequestContextGetter* request_context_getter) { 676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 677 678 URLRequestContext* context = request_context_getter->GetURLRequestContext(); 679 context->set_referrer_charset(referrer_charset); 680 681 rdh->BeginDownload(url, 682 referrer, 683 save_info, 684 true, // Show "Save as" UI. 685 render_process_host_id, 686 render_view_id, 687 context); 688} 689 690void CancelDownloadRequest(ResourceDispatcherHost* rdh, 691 int render_process_id, 692 int request_id) { 693 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 694 rdh->CancelRequest(render_process_id, request_id, false); 695} 696 697int GetUniquePathNumberWithCrDownload(const FilePath& path) { 698 const int kMaxAttempts = 100; 699 700 if (!file_util::PathExists(path) && 701 !file_util::PathExists(GetCrDownloadPath(path))) 702 return 0; 703 704 FilePath new_path; 705 for (int count = 1; count <= kMaxAttempts; ++count) { 706 new_path = FilePath(path); 707 AppendNumberToPath(&new_path, count); 708 709 if (!file_util::PathExists(new_path) && 710 !file_util::PathExists(GetCrDownloadPath(new_path))) 711 return count; 712 } 713 714 return -1; 715} 716 717FilePath GetCrDownloadPath(const FilePath& suggested_path) { 718 FilePath::StringType file_name; 719 base::SStringPrintf( 720 &file_name, 721 PRFilePathLiteral FILE_PATH_LITERAL(".crdownload"), 722 suggested_path.value().c_str()); 723 return FilePath(file_name); 724} 725 726// TODO(erikkay,phajdan.jr): This is apparently not being exercised in tests. 727bool IsDangerous(DownloadCreateInfo* info, Profile* profile) { 728 // Downloads can be marked as dangerous for two reasons: 729 // a) They have a dangerous-looking filename 730 // b) They are an extension that is not from the gallery 731 if (IsExecutableFile(info->suggested_path.BaseName())) { 732 return true; 733 } else if (info->is_extension_install) { 734 ExtensionsService* service = profile->GetExtensionsService(); 735 if (!service || 736 !service->IsDownloadFromGallery(info->url, info->referrer_url)) { 737 return true; 738 } 739 } 740 return false; 741} 742 743} // namespace download_util 744