| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // Download utility implementation | 5 // Download utility implementation |
| 6 | 6 |
| 7 #include "chrome/browser/download/download_util.h" | 7 #include "chrome/browser/download/download_util.h" |
| 8 | 8 |
| 9 #if defined(OS_WIN) | 9 #if defined(OS_WIN) |
| 10 #include <shobjidl.h> | 10 #include <shobjidl.h> |
| 11 #endif | 11 #endif |
| 12 #include <string> | 12 #include <string> |
| 13 | 13 |
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/i18n/rtl.h" | 15 #include "base/i18n/rtl.h" |
| 16 #include "base/i18n/time_formatting.h" | 16 #include "base/i18n/time_formatting.h" |
| 17 #include "base/lazy_instance.h" | 17 #include "base/lazy_instance.h" |
| 18 #include "base/metrics/histogram.h" | |
| 19 #include "base/path_service.h" | 18 #include "base/path_service.h" |
| 20 #include "base/string16.h" | 19 #include "base/string16.h" |
| 21 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 22 #include "base/stringprintf.h" | 21 #include "base/stringprintf.h" |
| 23 #include "base/sys_string_conversions.h" | 22 #include "base/sys_string_conversions.h" |
| 24 #include "base/threading/thread_restrictions.h" | 23 #include "base/threading/thread_restrictions.h" |
| 25 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
| 26 #include "base/value_conversions.h" | 25 #include "base/value_conversions.h" |
| 27 #include "base/values.h" | 26 #include "base/values.h" |
| 28 #include "base/win/windows_version.h" | 27 #include "base/win/windows_version.h" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 const std::string& mime_type, | 105 const std::string& mime_type, |
| 107 FilePath* generated_name) { | 106 FilePath* generated_name) { |
| 108 string16 default_file_name( | 107 string16 default_file_name( |
| 109 l10n_util::GetStringUTF16(IDS_DEFAULT_DOWNLOAD_FILENAME)); | 108 l10n_util::GetStringUTF16(IDS_DEFAULT_DOWNLOAD_FILENAME)); |
| 110 | 109 |
| 111 *generated_name = net::GenerateFileName(url, content_disposition, | 110 *generated_name = net::GenerateFileName(url, content_disposition, |
| 112 referrer_charset, suggested_name, | 111 referrer_charset, suggested_name, |
| 113 mime_type, default_file_name); | 112 mime_type, default_file_name); |
| 114 } | 113 } |
| 115 | 114 |
| 116 // All possible error codes from the network module. Note that the error codes | |
| 117 // are all positive (since histograms expect positive sample values). | |
| 118 const int kAllNetErrorCodes[] = { | |
| 119 #define NET_ERROR(label, value) -(value), | |
| 120 #include "net/base/net_error_list.h" | |
| 121 #undef NET_ERROR | |
| 122 }; | |
| 123 | |
| 124 } // namespace | 115 } // namespace |
| 125 | 116 |
| 126 // Download temporary file creation -------------------------------------------- | 117 // Download temporary file creation -------------------------------------------- |
| 127 | 118 |
| 128 class DefaultDownloadDirectory { | 119 class DefaultDownloadDirectory { |
| 129 public: | 120 public: |
| 130 const FilePath& path() const { return path_; } | 121 const FilePath& path() const { return path_; } |
| 131 private: | 122 private: |
| 132 DefaultDownloadDirectory() { | 123 DefaultDownloadDirectory() { |
| 133 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path_)) { | 124 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path_)) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 | 169 |
| 179 void GenerateFileNameFromSuggestedName(const GURL& url, | 170 void GenerateFileNameFromSuggestedName(const GURL& url, |
| 180 const std::string& suggested_name, | 171 const std::string& suggested_name, |
| 181 const std::string& mime_type, | 172 const std::string& mime_type, |
| 182 FilePath* generated_name) { | 173 FilePath* generated_name) { |
| 183 // TODO(asanka): We should pass in a valid referrer_charset here. | 174 // TODO(asanka): We should pass in a valid referrer_charset here. |
| 184 GenerateFileNameInternal(url, std::string(), std::string(), | 175 GenerateFileNameInternal(url, std::string(), std::string(), |
| 185 suggested_name, mime_type, generated_name); | 176 suggested_name, mime_type, generated_name); |
| 186 } | 177 } |
| 187 | 178 |
| 188 void RecordDownloadCount(DownloadCountTypes type) { | |
| 189 UMA_HISTOGRAM_ENUMERATION( | |
| 190 "Download.Counts", type, DOWNLOAD_COUNT_TYPES_LAST_ENTRY); | |
| 191 } | |
| 192 | |
| 193 void RecordDownloadCompleted(const base::TimeTicks& start) { | |
| 194 download_util::RecordDownloadCount(download_util::COMPLETED_COUNT); | |
| 195 UMA_HISTOGRAM_LONG_TIMES("Download.Time", (base::TimeTicks::Now() - start)); | |
| 196 } | |
| 197 | |
| 198 void RecordDownloadInterrupted(int error, int64 received, int64 total) { | |
| 199 download_util::RecordDownloadCount(download_util::INTERRUPTED_COUNT); | |
| 200 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | |
| 201 "Download.InterruptedError", | |
| 202 -error, | |
| 203 base::CustomHistogram::ArrayToCustomRanges( | |
| 204 kAllNetErrorCodes, arraysize(kAllNetErrorCodes))); | |
| 205 | |
| 206 // The maximum should be 2^kBuckets, to have the logarithmic bucket | |
| 207 // boundaries fall on powers of 2. | |
| 208 static const int kBuckets = 30; | |
| 209 static const int64 kMaxKb = 1 << kBuckets; // One Terabyte, in Kilobytes. | |
| 210 int64 delta_bytes = total - received; | |
| 211 bool unknown_size = total <= 0; | |
| 212 int64 received_kb = received / 1024; | |
| 213 int64 total_kb = total / 1024; | |
| 214 UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedReceivedSizeK", | |
| 215 received_kb, | |
| 216 1, | |
| 217 kMaxKb, | |
| 218 kBuckets); | |
| 219 if (!unknown_size) { | |
| 220 UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedTotalSizeK", | |
| 221 total_kb, | |
| 222 1, | |
| 223 kMaxKb, | |
| 224 kBuckets); | |
| 225 if (delta_bytes >= 0) { | |
| 226 UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedOverrunBytes", | |
| 227 delta_bytes, | |
| 228 1, | |
| 229 kMaxKb, | |
| 230 kBuckets); | |
| 231 } else { | |
| 232 UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedUnderrunBytes", | |
| 233 -delta_bytes, | |
| 234 1, | |
| 235 kMaxKb, | |
| 236 kBuckets); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 UMA_HISTOGRAM_BOOLEAN("Download.InterruptedUnknownSize", unknown_size); | |
| 241 } | |
| 242 | |
| 243 namespace { | |
| 244 | |
| 245 enum DownloadContent { | |
| 246 DOWNLOAD_CONTENT_UNRECOGNIZED = 0, | |
| 247 DOWNLOAD_CONTENT_TEXT = 1, | |
| 248 DOWNLOAD_CONTENT_IMAGE = 2, | |
| 249 DOWNLOAD_CONTENT_AUDIO = 3, | |
| 250 DOWNLOAD_CONTENT_VIDEO = 4, | |
| 251 DOWNLOAD_CONTENT_OCTET_STREAM = 5, | |
| 252 DOWNLOAD_CONTENT_PDF = 6, | |
| 253 DOWNLOAD_CONTENT_DOC = 7, | |
| 254 DOWNLOAD_CONTENT_XLS = 8, | |
| 255 DOWNLOAD_CONTENT_PPT = 9, | |
| 256 DOWNLOAD_CONTENT_ARCHIVE = 10, | |
| 257 DOWNLOAD_CONTENT_EXE = 11, | |
| 258 DOWNLOAD_CONTENT_DMG = 12, | |
| 259 DOWNLOAD_CONTENT_CRX = 13, | |
| 260 DOWNLOAD_CONTENT_MAX = 14, | |
| 261 }; | |
| 262 | |
| 263 struct MimeTypeToDownloadContent { | |
| 264 const char* mime_type; | |
| 265 DownloadContent download_content; | |
| 266 }; | |
| 267 | |
| 268 static MimeTypeToDownloadContent kMapMimeTypeToDownloadContent[] = { | |
| 269 {"application/octet-stream", DOWNLOAD_CONTENT_OCTET_STREAM}, | |
| 270 {"binary/octet-stream", DOWNLOAD_CONTENT_OCTET_STREAM}, | |
| 271 {"application/pdf", DOWNLOAD_CONTENT_PDF}, | |
| 272 {"application/msword", DOWNLOAD_CONTENT_DOC}, | |
| 273 {"application/vnd.ms-excel", DOWNLOAD_CONTENT_XLS}, | |
| 274 {"application/vns.ms-powerpoint", DOWNLOAD_CONTENT_PPT}, | |
| 275 {"application/zip", DOWNLOAD_CONTENT_ARCHIVE}, | |
| 276 {"application/x-gzip", DOWNLOAD_CONTENT_ARCHIVE}, | |
| 277 {"application/x-rar-compressed", DOWNLOAD_CONTENT_ARCHIVE}, | |
| 278 {"application/x-tar", DOWNLOAD_CONTENT_ARCHIVE}, | |
| 279 {"application/x-bzip", DOWNLOAD_CONTENT_ARCHIVE}, | |
| 280 {"application/x-exe", DOWNLOAD_CONTENT_EXE}, | |
| 281 {"application/x-apple-diskimage", DOWNLOAD_CONTENT_DMG}, | |
| 282 {"application/x-chrome-extension", DOWNLOAD_CONTENT_CRX}, | |
| 283 }; | |
| 284 | |
| 285 } // namespace | |
| 286 | |
| 287 void RecordDownloadMimeType(const std::string& mime_type_string) { | |
| 288 DownloadContent download_content = DOWNLOAD_CONTENT_UNRECOGNIZED; | |
| 289 | |
| 290 // Look up exact matches. | |
| 291 for (size_t i = 0; i < arraysize(kMapMimeTypeToDownloadContent); ++i) { | |
| 292 const MimeTypeToDownloadContent& entry = | |
| 293 kMapMimeTypeToDownloadContent[i]; | |
| 294 if (mime_type_string == entry.mime_type) { | |
| 295 download_content = entry.download_content; | |
| 296 break; | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 // Do partial matches. | |
| 301 if (download_content == DOWNLOAD_CONTENT_UNRECOGNIZED) { | |
| 302 if (StartsWithASCII(mime_type_string, "text/", true)) { | |
| 303 download_content = DOWNLOAD_CONTENT_TEXT; | |
| 304 } else if (StartsWithASCII(mime_type_string, "image/", true)) { | |
| 305 download_content = DOWNLOAD_CONTENT_IMAGE; | |
| 306 } else if (StartsWithASCII(mime_type_string, "audio/", true)) { | |
| 307 download_content = DOWNLOAD_CONTENT_AUDIO; | |
| 308 } else if (StartsWithASCII(mime_type_string, "video/", true)) { | |
| 309 download_content = DOWNLOAD_CONTENT_VIDEO; | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 // Record the value. | |
| 314 UMA_HISTOGRAM_ENUMERATION("Download.ContentType", | |
| 315 download_content, | |
| 316 DOWNLOAD_CONTENT_MAX); | |
| 317 } | |
| 318 | |
| 319 // Download progress painting -------------------------------------------------- | 179 // Download progress painting -------------------------------------------------- |
| 320 | 180 |
| 321 // Common bitmaps used for download progress animations. We load them once the | 181 // Common bitmaps used for download progress animations. We load them once the |
| 322 // first time we do a progress paint, then reuse them as they are always the | 182 // first time we do a progress paint, then reuse them as they are always the |
| 323 // same. | 183 // same. |
| 324 SkBitmap* g_foreground_16 = NULL; | 184 SkBitmap* g_foreground_16 = NULL; |
| 325 SkBitmap* g_background_16 = NULL; | 185 SkBitmap* g_background_16 = NULL; |
| 326 SkBitmap* g_foreground_32 = NULL; | 186 SkBitmap* g_foreground_32 = NULL; |
| 327 SkBitmap* g_background_32 = NULL; | 187 SkBitmap* g_background_32 = NULL; |
| 328 | 188 |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 | 632 |
| 773 rdh->BeginDownload(url, | 633 rdh->BeginDownload(url, |
| 774 referrer, | 634 referrer, |
| 775 save_info, | 635 save_info, |
| 776 true, // Show "Save as" UI. | 636 true, // Show "Save as" UI. |
| 777 render_process_host_id, | 637 render_process_host_id, |
| 778 render_view_id, | 638 render_view_id, |
| 779 *context); | 639 *context); |
| 780 } | 640 } |
| 781 | 641 |
| 782 void NotifyDownloadInitiated(int render_process_id, int render_view_id) { | |
| 783 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 784 RenderViewHost* rvh = RenderViewHost::FromID(render_process_id, | |
| 785 render_view_id); | |
| 786 if (!rvh) | |
| 787 return; | |
| 788 | |
| 789 NotificationService::current()->Notify( | |
| 790 chrome::NOTIFICATION_DOWNLOAD_INITIATED, Source<RenderViewHost>(rvh), | |
| 791 NotificationService::NoDetails()); | |
| 792 } | |
| 793 | |
| 794 int GetUniquePathNumberWithCrDownload(const FilePath& path) { | 642 int GetUniquePathNumberWithCrDownload(const FilePath& path) { |
| 795 if (!file_util::PathExists(path) && | 643 if (!file_util::PathExists(path) && |
| 796 !file_util::PathExists(GetCrDownloadPath(path))) | 644 !file_util::PathExists(GetCrDownloadPath(path))) |
| 797 return 0; | 645 return 0; |
| 798 | 646 |
| 799 FilePath new_path; | 647 FilePath new_path; |
| 800 for (int count = 1; count <= kMaxUniqueFiles; ++count) { | 648 for (int count = 1; count <= kMaxUniqueFiles; ++count) { |
| 801 new_path = FilePath(path); | 649 new_path = FilePath(path); |
| 802 AppendNumberToPath(&new_path, count); | 650 AppendNumberToPath(&new_path, count); |
| 803 | 651 |
| 804 if (!file_util::PathExists(new_path) && | 652 if (!file_util::PathExists(new_path) && |
| 805 !file_util::PathExists(GetCrDownloadPath(new_path))) | 653 !file_util::PathExists(GetCrDownloadPath(new_path))) |
| 806 return count; | 654 return count; |
| 807 } | 655 } |
| 808 | 656 |
| 809 return -1; | 657 return -1; |
| 810 } | 658 } |
| 811 | 659 |
| 812 FilePath GetCrDownloadPath(const FilePath& suggested_path) { | 660 FilePath GetCrDownloadPath(const FilePath& suggested_path) { |
| 813 FilePath::StringType file_name; | 661 FilePath::StringType file_name; |
| 814 base::SStringPrintf( | 662 base::SStringPrintf( |
| 815 &file_name, | 663 &file_name, |
| 816 PRFilePathLiteral FILE_PATH_LITERAL(".crdownload"), | 664 PRFilePathLiteral FILE_PATH_LITERAL(".crdownload"), |
| 817 suggested_path.value().c_str()); | 665 suggested_path.value().c_str()); |
| 818 return FilePath(file_name); | 666 return FilePath(file_name); |
| 819 } | 667 } |
| 820 | 668 |
| 821 } // namespace download_util | 669 } // namespace download_util |
| OLD | NEW |