• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "content/browser/download/download_stats.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/strings/string_util.h"
10 #include "content/browser/download/download_resource_handler.h"
11 #include "content/public/browser/download_interrupt_reasons.h"
12 #include "net/http/http_content_disposition.h"
13 
14 namespace content {
15 
16 namespace {
17 
18 // All possible error codes from the network module. Note that the error codes
19 // are all positive (since histograms expect positive sample values).
20 const int kAllInterruptReasonCodes[] = {
21 #define INTERRUPT_REASON(label, value) (value),
22 #include "content/public/browser/download_interrupt_reason_values.h"
23 #undef INTERRUPT_REASON
24 };
25 
26 // These values are based on net::HttpContentDisposition::ParseResult values.
27 // Values other than HEADER_PRESENT and IS_VALID are only measured if |IS_VALID|
28 // is true.
29 enum ContentDispositionCountTypes {
30   // Count of downloads which had a Content-Disposition headers. The total
31   // number of downloads is measured by UNTHROTTLED_COUNT.
32   CONTENT_DISPOSITION_HEADER_PRESENT = 0,
33 
34   // At least one of 'name', 'filename' or 'filenae*' attributes were valid and
35   // yielded a non-empty filename.
36   CONTENT_DISPOSITION_IS_VALID,
37 
38   // The following enum values correspond to
39   // net::HttpContentDisposition::ParseResult.
40   CONTENT_DISPOSITION_HAS_DISPOSITION_TYPE,
41   CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE,
42   CONTENT_DISPOSITION_HAS_NAME,
43   CONTENT_DISPOSITION_HAS_FILENAME,
44   CONTENT_DISPOSITION_HAS_EXT_FILENAME,
45   CONTENT_DISPOSITION_HAS_NON_ASCII_STRINGS,
46   CONTENT_DISPOSITION_HAS_PERCENT_ENCODED_STRINGS,
47   CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS,
48 
49   // Only have the 'name' attribute is present.
50   CONTENT_DISPOSITION_HAS_NAME_ONLY,
51 
52   CONTENT_DISPOSITION_LAST_ENTRY
53 };
54 
RecordContentDispositionCount(ContentDispositionCountTypes type,bool record)55 void RecordContentDispositionCount(ContentDispositionCountTypes type,
56                                    bool record) {
57   if (!record)
58     return;
59   UMA_HISTOGRAM_ENUMERATION(
60       "Download.ContentDisposition", type, CONTENT_DISPOSITION_LAST_ENTRY);
61 }
62 
RecordContentDispositionCountFlag(ContentDispositionCountTypes type,int flags_to_test,net::HttpContentDisposition::ParseResultFlags flag)63 void RecordContentDispositionCountFlag(
64     ContentDispositionCountTypes type,
65     int flags_to_test,
66     net::HttpContentDisposition::ParseResultFlags flag) {
67   RecordContentDispositionCount(type, (flags_to_test & flag) == flag);
68 }
69 
70 // Do not insert, delete, or reorder; this is being histogrammed. Append only.
71 // All of the download_extensions.cc file types should be in this list.
72 const base::FilePath::CharType* kDangerousFileTypes[] = {
73   FILE_PATH_LITERAL(".ad"),
74   FILE_PATH_LITERAL(".ade"),
75   FILE_PATH_LITERAL(".adp"),
76   FILE_PATH_LITERAL(".ah"),
77   FILE_PATH_LITERAL(".apk"),
78   FILE_PATH_LITERAL(".app"),
79   FILE_PATH_LITERAL(".application"),
80   FILE_PATH_LITERAL(".asp"),
81   FILE_PATH_LITERAL(".asx"),
82   FILE_PATH_LITERAL(".bas"),
83   FILE_PATH_LITERAL(".bash"),
84   FILE_PATH_LITERAL(".bat"),
85   FILE_PATH_LITERAL(".cfg"),
86   FILE_PATH_LITERAL(".chi"),
87   FILE_PATH_LITERAL(".chm"),
88   FILE_PATH_LITERAL(".class"),
89   FILE_PATH_LITERAL(".cmd"),
90   FILE_PATH_LITERAL(".com"),
91   FILE_PATH_LITERAL(".command"),
92   FILE_PATH_LITERAL(".crt"),
93   FILE_PATH_LITERAL(".crx"),
94   FILE_PATH_LITERAL(".csh"),
95   FILE_PATH_LITERAL(".deb"),
96   FILE_PATH_LITERAL(".dex"),
97   FILE_PATH_LITERAL(".dll"),
98   FILE_PATH_LITERAL(".drv"),
99   FILE_PATH_LITERAL(".exe"),
100   FILE_PATH_LITERAL(".fxp"),
101   FILE_PATH_LITERAL(".grp"),
102   FILE_PATH_LITERAL(".hlp"),
103   FILE_PATH_LITERAL(".hta"),
104   FILE_PATH_LITERAL(".htm"),
105   FILE_PATH_LITERAL(".html"),
106   FILE_PATH_LITERAL(".htt"),
107   FILE_PATH_LITERAL(".inf"),
108   FILE_PATH_LITERAL(".ini"),
109   FILE_PATH_LITERAL(".ins"),
110   FILE_PATH_LITERAL(".isp"),
111   FILE_PATH_LITERAL(".jar"),
112   FILE_PATH_LITERAL(".jnlp"),
113   FILE_PATH_LITERAL(".user.js"),
114   FILE_PATH_LITERAL(".js"),
115   FILE_PATH_LITERAL(".jse"),
116   FILE_PATH_LITERAL(".ksh"),
117   FILE_PATH_LITERAL(".lnk"),
118   FILE_PATH_LITERAL(".local"),
119   FILE_PATH_LITERAL(".mad"),
120   FILE_PATH_LITERAL(".maf"),
121   FILE_PATH_LITERAL(".mag"),
122   FILE_PATH_LITERAL(".mam"),
123   FILE_PATH_LITERAL(".manifest"),
124   FILE_PATH_LITERAL(".maq"),
125   FILE_PATH_LITERAL(".mar"),
126   FILE_PATH_LITERAL(".mas"),
127   FILE_PATH_LITERAL(".mat"),
128   FILE_PATH_LITERAL(".mau"),
129   FILE_PATH_LITERAL(".mav"),
130   FILE_PATH_LITERAL(".maw"),
131   FILE_PATH_LITERAL(".mda"),
132   FILE_PATH_LITERAL(".mdb"),
133   FILE_PATH_LITERAL(".mde"),
134   FILE_PATH_LITERAL(".mdt"),
135   FILE_PATH_LITERAL(".mdw"),
136   FILE_PATH_LITERAL(".mdz"),
137   FILE_PATH_LITERAL(".mht"),
138   FILE_PATH_LITERAL(".mhtml"),
139   FILE_PATH_LITERAL(".mmc"),
140   FILE_PATH_LITERAL(".mof"),
141   FILE_PATH_LITERAL(".msc"),
142   FILE_PATH_LITERAL(".msh"),
143   FILE_PATH_LITERAL(".mshxml"),
144   FILE_PATH_LITERAL(".msi"),
145   FILE_PATH_LITERAL(".msp"),
146   FILE_PATH_LITERAL(".mst"),
147   FILE_PATH_LITERAL(".ocx"),
148   FILE_PATH_LITERAL(".ops"),
149   FILE_PATH_LITERAL(".pcd"),
150   FILE_PATH_LITERAL(".pif"),
151   FILE_PATH_LITERAL(".pkg"),
152   FILE_PATH_LITERAL(".pl"),
153   FILE_PATH_LITERAL(".plg"),
154   FILE_PATH_LITERAL(".prf"),
155   FILE_PATH_LITERAL(".prg"),
156   FILE_PATH_LITERAL(".pst"),
157   FILE_PATH_LITERAL(".py"),
158   FILE_PATH_LITERAL(".pyc"),
159   FILE_PATH_LITERAL(".pyw"),
160   FILE_PATH_LITERAL(".rb"),
161   FILE_PATH_LITERAL(".reg"),
162   FILE_PATH_LITERAL(".rpm"),
163   FILE_PATH_LITERAL(".scf"),
164   FILE_PATH_LITERAL(".scr"),
165   FILE_PATH_LITERAL(".sct"),
166   FILE_PATH_LITERAL(".sh"),
167   FILE_PATH_LITERAL(".shar"),
168   FILE_PATH_LITERAL(".shb"),
169   FILE_PATH_LITERAL(".shs"),
170   FILE_PATH_LITERAL(".shtm"),
171   FILE_PATH_LITERAL(".shtml"),
172   FILE_PATH_LITERAL(".spl"),
173   FILE_PATH_LITERAL(".svg"),
174   FILE_PATH_LITERAL(".swf"),
175   FILE_PATH_LITERAL(".sys"),
176   FILE_PATH_LITERAL(".tcsh"),
177   FILE_PATH_LITERAL(".url"),
178   FILE_PATH_LITERAL(".vb"),
179   FILE_PATH_LITERAL(".vbe"),
180   FILE_PATH_LITERAL(".vbs"),
181   FILE_PATH_LITERAL(".vsd"),
182   FILE_PATH_LITERAL(".vsmacros"),
183   FILE_PATH_LITERAL(".vss"),
184   FILE_PATH_LITERAL(".vst"),
185   FILE_PATH_LITERAL(".vsw"),
186   FILE_PATH_LITERAL(".ws"),
187   FILE_PATH_LITERAL(".wsc"),
188   FILE_PATH_LITERAL(".wsf"),
189   FILE_PATH_LITERAL(".wsh"),
190   FILE_PATH_LITERAL(".xbap"),
191   FILE_PATH_LITERAL(".xht"),
192   FILE_PATH_LITERAL(".xhtm"),
193   FILE_PATH_LITERAL(".xhtml"),
194   FILE_PATH_LITERAL(".xml"),
195   FILE_PATH_LITERAL(".xsl"),
196   FILE_PATH_LITERAL(".xslt")
197 };
198 
199 // Maps extensions to their matching UMA histogram int value.
GetDangerousFileType(const base::FilePath & file_path)200 int GetDangerousFileType(const base::FilePath& file_path) {
201   for (size_t i = 0; i < arraysize(kDangerousFileTypes); ++i) {
202     if (file_path.MatchesExtension(kDangerousFileTypes[i]))
203       return i + 1;
204   }
205   return 0;  // Unknown extension.
206 }
207 
208 } // namespace
209 
RecordDownloadCount(DownloadCountTypes type)210 void RecordDownloadCount(DownloadCountTypes type) {
211   UMA_HISTOGRAM_ENUMERATION(
212       "Download.Counts", type, DOWNLOAD_COUNT_TYPES_LAST_ENTRY);
213 }
214 
RecordDownloadSource(DownloadSource source)215 void RecordDownloadSource(DownloadSource source) {
216   UMA_HISTOGRAM_ENUMERATION(
217       "Download.Sources", source, DOWNLOAD_SOURCE_LAST_ENTRY);
218 }
219 
RecordDownloadCompleted(const base::TimeTicks & start,int64 download_len)220 void RecordDownloadCompleted(const base::TimeTicks& start, int64 download_len) {
221   RecordDownloadCount(COMPLETED_COUNT);
222   UMA_HISTOGRAM_LONG_TIMES("Download.Time", (base::TimeTicks::Now() - start));
223   int64 max = 1024 * 1024 * 1024;  // One Terabyte.
224   download_len /= 1024;  // In Kilobytes
225   UMA_HISTOGRAM_CUSTOM_COUNTS("Download.DownloadSize",
226                               download_len,
227                               1,
228                               max,
229                               256);
230 }
231 
RecordDownloadInterrupted(DownloadInterruptReason reason,int64 received,int64 total)232 void RecordDownloadInterrupted(DownloadInterruptReason reason,
233                                int64 received,
234                                int64 total) {
235   RecordDownloadCount(INTERRUPTED_COUNT);
236   UMA_HISTOGRAM_CUSTOM_ENUMERATION(
237       "Download.InterruptedReason",
238       reason,
239       base::CustomHistogram::ArrayToCustomRanges(
240           kAllInterruptReasonCodes, arraysize(kAllInterruptReasonCodes)));
241 
242   // The maximum should be 2^kBuckets, to have the logarithmic bucket
243   // boundaries fall on powers of 2.
244   static const int kBuckets = 30;
245   static const int64 kMaxKb = 1 << kBuckets;  // One Terabyte, in Kilobytes.
246   int64 delta_bytes = total - received;
247   bool unknown_size = total <= 0;
248   int64 received_kb = received / 1024;
249   int64 total_kb = total / 1024;
250   UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedReceivedSizeK",
251                               received_kb,
252                               1,
253                               kMaxKb,
254                               kBuckets);
255   if (!unknown_size) {
256     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedTotalSizeK",
257                                 total_kb,
258                                 1,
259                                 kMaxKb,
260                                 kBuckets);
261     if (delta_bytes == 0) {
262       RecordDownloadCount(INTERRUPTED_AT_END_COUNT);
263       UMA_HISTOGRAM_CUSTOM_ENUMERATION(
264           "Download.InterruptedAtEndReason",
265           reason,
266           base::CustomHistogram::ArrayToCustomRanges(
267               kAllInterruptReasonCodes,
268               arraysize(kAllInterruptReasonCodes)));
269     } else if (delta_bytes > 0) {
270       UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedOverrunBytes",
271                                   delta_bytes,
272                                   1,
273                                   kMaxKb,
274                                   kBuckets);
275     } else {
276       UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedUnderrunBytes",
277                                   -delta_bytes,
278                                   1,
279                                   kMaxKb,
280                                   kBuckets);
281     }
282   }
283 
284   UMA_HISTOGRAM_BOOLEAN("Download.InterruptedUnknownSize", unknown_size);
285 }
286 
RecordMaliciousDownloadClassified(DownloadDangerType danger_type)287 void RecordMaliciousDownloadClassified(DownloadDangerType danger_type) {
288   UMA_HISTOGRAM_ENUMERATION("Download.MaliciousDownloadClassified",
289                             danger_type,
290                             DOWNLOAD_DANGER_TYPE_MAX);
291 }
292 
RecordDangerousDownloadAccept(DownloadDangerType danger_type,const base::FilePath & file_path)293 void RecordDangerousDownloadAccept(DownloadDangerType danger_type,
294                                    const base::FilePath& file_path) {
295   UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
296                             danger_type,
297                             DOWNLOAD_DANGER_TYPE_MAX);
298   if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
299     UMA_HISTOGRAM_SPARSE_SLOWLY(
300         "Download.DangerousFile.DangerousDownloadValidated",
301         GetDangerousFileType(file_path));
302   }
303 }
304 
RecordDangerousDownloadDiscard(DownloadDiscardReason reason,DownloadDangerType danger_type,const base::FilePath & file_path)305 void RecordDangerousDownloadDiscard(DownloadDiscardReason reason,
306                                     DownloadDangerType danger_type,
307                                     const base::FilePath& file_path) {
308   switch (reason) {
309     case DOWNLOAD_DISCARD_DUE_TO_USER_ACTION:
310       UMA_HISTOGRAM_ENUMERATION(
311           "Download.UserDiscard", danger_type, DOWNLOAD_DANGER_TYPE_MAX);
312       if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
313         UMA_HISTOGRAM_SPARSE_SLOWLY("Download.DangerousFile.UserDiscard",
314                                     GetDangerousFileType(file_path));
315       }
316       break;
317     case DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN:
318       UMA_HISTOGRAM_ENUMERATION(
319           "Download.Discard", danger_type, DOWNLOAD_DANGER_TYPE_MAX);
320       if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
321         UMA_HISTOGRAM_SPARSE_SLOWLY("Download.DangerousFile.Discard",
322                                     GetDangerousFileType(file_path));
323       }
324       break;
325     default:
326       NOTREACHED();
327   }
328 }
329 
RecordDownloadWriteSize(size_t data_len)330 void RecordDownloadWriteSize(size_t data_len) {
331   int max = 1024 * 1024;  // One Megabyte.
332   UMA_HISTOGRAM_CUSTOM_COUNTS("Download.WriteSize", data_len, 1, max, 256);
333 }
334 
RecordDownloadWriteLoopCount(int count)335 void RecordDownloadWriteLoopCount(int count) {
336   UMA_HISTOGRAM_ENUMERATION("Download.WriteLoopCount", count, 20);
337 }
338 
RecordAcceptsRanges(const std::string & accepts_ranges,int64 download_len,bool has_strong_validator)339 void RecordAcceptsRanges(const std::string& accepts_ranges,
340                          int64 download_len,
341                          bool has_strong_validator) {
342   int64 max = 1024 * 1024 * 1024;  // One Terabyte.
343   download_len /= 1024;  // In Kilobytes
344   static const int kBuckets = 50;
345 
346   if (LowerCaseEqualsASCII(accepts_ranges, "none")) {
347     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesNone.KBytes",
348                                 download_len,
349                                 1,
350                                 max,
351                                 kBuckets);
352   } else if (LowerCaseEqualsASCII(accepts_ranges, "bytes")) {
353     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesBytes.KBytes",
354                                 download_len,
355                                 1,
356                                 max,
357                                 kBuckets);
358     if (has_strong_validator)
359       RecordDownloadCount(STRONG_VALIDATOR_AND_ACCEPTS_RANGES);
360   } else {
361     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesMissingOrInvalid.KBytes",
362                                 download_len,
363                                 1,
364                                 max,
365                                 kBuckets);
366   }
367 }
368 
369 namespace {
370 
371 enum DownloadContent {
372   DOWNLOAD_CONTENT_UNRECOGNIZED = 0,
373   DOWNLOAD_CONTENT_TEXT = 1,
374   DOWNLOAD_CONTENT_IMAGE = 2,
375   DOWNLOAD_CONTENT_AUDIO = 3,
376   DOWNLOAD_CONTENT_VIDEO = 4,
377   DOWNLOAD_CONTENT_OCTET_STREAM = 5,
378   DOWNLOAD_CONTENT_PDF = 6,
379   DOWNLOAD_CONTENT_DOC = 7,
380   DOWNLOAD_CONTENT_XLS = 8,
381   DOWNLOAD_CONTENT_PPT = 9,
382   DOWNLOAD_CONTENT_ARCHIVE = 10,
383   DOWNLOAD_CONTENT_EXE = 11,
384   DOWNLOAD_CONTENT_DMG = 12,
385   DOWNLOAD_CONTENT_CRX = 13,
386   DOWNLOAD_CONTENT_MAX = 14,
387 };
388 
389 struct MimeTypeToDownloadContent {
390   const char* mime_type;
391   DownloadContent download_content;
392 };
393 
394 static MimeTypeToDownloadContent kMapMimeTypeToDownloadContent[] = {
395   {"application/octet-stream", DOWNLOAD_CONTENT_OCTET_STREAM},
396   {"binary/octet-stream", DOWNLOAD_CONTENT_OCTET_STREAM},
397   {"application/pdf", DOWNLOAD_CONTENT_PDF},
398   {"application/msword", DOWNLOAD_CONTENT_DOC},
399   {"application/vnd.ms-excel", DOWNLOAD_CONTENT_XLS},
400   {"application/vns.ms-powerpoint", DOWNLOAD_CONTENT_PPT},
401   {"application/zip", DOWNLOAD_CONTENT_ARCHIVE},
402   {"application/x-gzip", DOWNLOAD_CONTENT_ARCHIVE},
403   {"application/x-rar-compressed", DOWNLOAD_CONTENT_ARCHIVE},
404   {"application/x-tar", DOWNLOAD_CONTENT_ARCHIVE},
405   {"application/x-bzip", DOWNLOAD_CONTENT_ARCHIVE},
406   {"application/x-exe", DOWNLOAD_CONTENT_EXE},
407   {"application/x-apple-diskimage", DOWNLOAD_CONTENT_DMG},
408   {"application/x-chrome-extension", DOWNLOAD_CONTENT_CRX},
409 };
410 
411 enum DownloadImage {
412   DOWNLOAD_IMAGE_UNRECOGNIZED = 0,
413   DOWNLOAD_IMAGE_GIF = 1,
414   DOWNLOAD_IMAGE_JPEG = 2,
415   DOWNLOAD_IMAGE_PNG = 3,
416   DOWNLOAD_IMAGE_TIFF = 4,
417   DOWNLOAD_IMAGE_ICON = 5,
418   DOWNLOAD_IMAGE_WEBP = 6,
419   DOWNLOAD_IMAGE_MAX = 7,
420 };
421 
422 struct MimeTypeToDownloadImage {
423   const char* mime_type;
424   DownloadImage download_image;
425 };
426 
427 static MimeTypeToDownloadImage kMapMimeTypeToDownloadImage[] = {
428   {"image/gif", DOWNLOAD_IMAGE_GIF},
429   {"image/jpeg", DOWNLOAD_IMAGE_JPEG},
430   {"image/png", DOWNLOAD_IMAGE_PNG},
431   {"image/tiff", DOWNLOAD_IMAGE_TIFF},
432   {"image/vnd.microsoft.icon", DOWNLOAD_IMAGE_ICON},
433   {"image/webp", DOWNLOAD_IMAGE_WEBP},
434 };
435 
RecordDownloadImageType(const std::string & mime_type_string)436 void RecordDownloadImageType(const std::string& mime_type_string) {
437   DownloadImage download_image = DOWNLOAD_IMAGE_UNRECOGNIZED;
438 
439   // Look up exact matches.
440   for (size_t i = 0; i < arraysize(kMapMimeTypeToDownloadImage); ++i) {
441     const MimeTypeToDownloadImage& entry = kMapMimeTypeToDownloadImage[i];
442     if (mime_type_string == entry.mime_type) {
443       download_image = entry.download_image;
444       break;
445     }
446   }
447 
448   UMA_HISTOGRAM_ENUMERATION("Download.ContentImageType",
449                             download_image,
450                             DOWNLOAD_IMAGE_MAX);
451 }
452 
453 }  // namespace
454 
RecordDownloadMimeType(const std::string & mime_type_string)455 void RecordDownloadMimeType(const std::string& mime_type_string) {
456   DownloadContent download_content = DOWNLOAD_CONTENT_UNRECOGNIZED;
457 
458   // Look up exact matches.
459   for (size_t i = 0; i < arraysize(kMapMimeTypeToDownloadContent); ++i) {
460     const MimeTypeToDownloadContent& entry = kMapMimeTypeToDownloadContent[i];
461     if (mime_type_string == entry.mime_type) {
462       download_content = entry.download_content;
463       break;
464     }
465   }
466 
467   // Do partial matches.
468   if (download_content == DOWNLOAD_CONTENT_UNRECOGNIZED) {
469     if (StartsWithASCII(mime_type_string, "text/", true)) {
470       download_content = DOWNLOAD_CONTENT_TEXT;
471     } else if (StartsWithASCII(mime_type_string, "image/", true)) {
472       download_content = DOWNLOAD_CONTENT_IMAGE;
473       RecordDownloadImageType(mime_type_string);
474     } else if (StartsWithASCII(mime_type_string, "audio/", true)) {
475       download_content = DOWNLOAD_CONTENT_AUDIO;
476     } else if (StartsWithASCII(mime_type_string, "video/", true)) {
477       download_content = DOWNLOAD_CONTENT_VIDEO;
478     }
479   }
480 
481   // Record the value.
482   UMA_HISTOGRAM_ENUMERATION("Download.ContentType",
483                             download_content,
484                             DOWNLOAD_CONTENT_MAX);
485 }
486 
RecordDownloadContentDisposition(const std::string & content_disposition_string)487 void RecordDownloadContentDisposition(
488     const std::string& content_disposition_string) {
489   if (content_disposition_string.empty())
490     return;
491   net::HttpContentDisposition content_disposition(content_disposition_string,
492                                                   std::string());
493   int result = content_disposition.parse_result_flags();
494 
495   bool is_valid = !content_disposition.filename().empty();
496   RecordContentDispositionCount(CONTENT_DISPOSITION_HEADER_PRESENT, true);
497   RecordContentDispositionCount(CONTENT_DISPOSITION_IS_VALID, is_valid);
498   if (!is_valid)
499     return;
500 
501   RecordContentDispositionCountFlag(
502       CONTENT_DISPOSITION_HAS_DISPOSITION_TYPE, result,
503       net::HttpContentDisposition::HAS_DISPOSITION_TYPE);
504   RecordContentDispositionCountFlag(
505       CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE, result,
506       net::HttpContentDisposition::HAS_UNKNOWN_DISPOSITION_TYPE);
507   RecordContentDispositionCountFlag(
508       CONTENT_DISPOSITION_HAS_NAME, result,
509       net::HttpContentDisposition::HAS_NAME);
510   RecordContentDispositionCountFlag(
511       CONTENT_DISPOSITION_HAS_FILENAME, result,
512       net::HttpContentDisposition::HAS_FILENAME);
513   RecordContentDispositionCountFlag(
514       CONTENT_DISPOSITION_HAS_EXT_FILENAME, result,
515       net::HttpContentDisposition::HAS_EXT_FILENAME);
516   RecordContentDispositionCountFlag(
517       CONTENT_DISPOSITION_HAS_NON_ASCII_STRINGS, result,
518       net::HttpContentDisposition::HAS_NON_ASCII_STRINGS);
519   RecordContentDispositionCountFlag(
520       CONTENT_DISPOSITION_HAS_PERCENT_ENCODED_STRINGS, result,
521       net::HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS);
522   RecordContentDispositionCountFlag(
523       CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS, result,
524       net::HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS);
525 
526   RecordContentDispositionCount(
527       CONTENT_DISPOSITION_HAS_NAME_ONLY,
528       (result & (net::HttpContentDisposition::HAS_NAME |
529                  net::HttpContentDisposition::HAS_FILENAME |
530                  net::HttpContentDisposition::HAS_EXT_FILENAME)) ==
531       net::HttpContentDisposition::HAS_NAME);
532 }
533 
RecordFileThreadReceiveBuffers(size_t num_buffers)534 void RecordFileThreadReceiveBuffers(size_t num_buffers) {
535     UMA_HISTOGRAM_CUSTOM_COUNTS(
536       "Download.FileThreadReceiveBuffers", num_buffers, 1,
537       100, 100);
538 }
539 
RecordBandwidth(double actual_bandwidth,double potential_bandwidth)540 void RecordBandwidth(double actual_bandwidth, double potential_bandwidth) {
541   UMA_HISTOGRAM_CUSTOM_COUNTS(
542       "Download.ActualBandwidth", actual_bandwidth, 1, 1000000000, 50);
543   UMA_HISTOGRAM_CUSTOM_COUNTS(
544       "Download.PotentialBandwidth", potential_bandwidth, 1, 1000000000, 50);
545   UMA_HISTOGRAM_PERCENTAGE(
546       "Download.BandwidthUsed",
547       (int) ((actual_bandwidth * 100)/ potential_bandwidth));
548 }
549 
RecordOpen(const base::Time & end,bool first)550 void RecordOpen(const base::Time& end, bool first) {
551   if (!end.is_null()) {
552     UMA_HISTOGRAM_LONG_TIMES("Download.OpenTime", (base::Time::Now() - end));
553     if (first) {
554       UMA_HISTOGRAM_LONG_TIMES("Download.FirstOpenTime",
555                               (base::Time::Now() - end));
556     }
557   }
558 }
559 
RecordClearAllSize(int size)560 void RecordClearAllSize(int size) {
561   UMA_HISTOGRAM_CUSTOM_COUNTS("Download.ClearAllSize",
562                               size,
563                               0/*min*/,
564                               (1 << 10)/*max*/,
565                               32/*num_buckets*/);
566 }
567 
RecordOpensOutstanding(int size)568 void RecordOpensOutstanding(int size) {
569   UMA_HISTOGRAM_CUSTOM_COUNTS("Download.OpensOutstanding",
570                               size,
571                               0/*min*/,
572                               (1 << 10)/*max*/,
573                               64/*num_buckets*/);
574 }
575 
RecordContiguousWriteTime(base::TimeDelta time_blocked)576 void RecordContiguousWriteTime(base::TimeDelta time_blocked) {
577   UMA_HISTOGRAM_TIMES("Download.FileThreadBlockedTime", time_blocked);
578 }
579 
580 // Record what percentage of the time we have the network flow controlled.
RecordNetworkBlockage(base::TimeDelta resource_handler_lifetime,base::TimeDelta resource_handler_blocked_time)581 void RecordNetworkBlockage(base::TimeDelta resource_handler_lifetime,
582                            base::TimeDelta resource_handler_blocked_time) {
583   int percentage = 0;
584   // Avoid division by zero errors.
585   if (resource_handler_blocked_time != base::TimeDelta()) {
586     percentage =
587         resource_handler_blocked_time * 100 / resource_handler_lifetime;
588   }
589 
590   UMA_HISTOGRAM_COUNTS_100("Download.ResourceHandlerBlockedPercentage",
591                            percentage);
592 }
593 
RecordFileBandwidth(size_t length,base::TimeDelta disk_write_time,base::TimeDelta elapsed_time)594 void RecordFileBandwidth(size_t length,
595                          base::TimeDelta disk_write_time,
596                          base::TimeDelta elapsed_time) {
597   size_t elapsed_time_ms = elapsed_time.InMilliseconds();
598   if (0u == elapsed_time_ms)
599     elapsed_time_ms = 1;
600   size_t disk_write_time_ms = disk_write_time.InMilliseconds();
601   if (0u == disk_write_time_ms)
602     disk_write_time_ms = 1;
603 
604   UMA_HISTOGRAM_CUSTOM_COUNTS(
605       "Download.BandwidthOverallBytesPerSecond",
606       (1000 * length / elapsed_time_ms), 1, 50000000, 50);
607   UMA_HISTOGRAM_CUSTOM_COUNTS(
608       "Download.BandwidthDiskBytesPerSecond",
609       (1000 * length / disk_write_time_ms), 1, 50000000, 50);
610   UMA_HISTOGRAM_COUNTS_100("Download.DiskBandwidthUsedPercentage",
611                            disk_write_time_ms * 100 / elapsed_time_ms);
612 }
613 
RecordDownloadFileRenameResultAfterRetry(base::TimeDelta time_since_first_failure,DownloadInterruptReason interrupt_reason)614 void RecordDownloadFileRenameResultAfterRetry(
615     base::TimeDelta time_since_first_failure,
616     DownloadInterruptReason interrupt_reason) {
617   if (interrupt_reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
618     UMA_HISTOGRAM_TIMES("Download.TimeToRenameSuccessAfterInitialFailure",
619                         time_since_first_failure);
620   } else {
621     UMA_HISTOGRAM_TIMES("Download.TimeToRenameFailureAfterInitialFailure",
622                         time_since_first_failure);
623   }
624 }
625 
RecordSavePackageEvent(SavePackageEvent event)626 void RecordSavePackageEvent(SavePackageEvent event) {
627   UMA_HISTOGRAM_ENUMERATION("Download.SavePackage",
628                             event,
629                             SAVE_PACKAGE_LAST_ENTRY);
630 }
631 
RecordOriginStateOnResumption(bool is_partial,int state)632 void RecordOriginStateOnResumption(bool is_partial,
633                                    int state) {
634   if (is_partial)
635     UMA_HISTOGRAM_ENUMERATION("Download.OriginStateOnPartialResumption", state,
636                               ORIGIN_STATE_ON_RESUMPTION_MAX);
637   else
638     UMA_HISTOGRAM_ENUMERATION("Download.OriginStateOnFullResumption", state,
639                               ORIGIN_STATE_ON_RESUMPTION_MAX);
640 }
641 
642 }  // namespace content
643