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