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
3 // found in the LICENSE file.
4
5 #include "chrome/renderer/plugins/plugin_uma.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "base/metrics/histogram_macros.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "content/public/common/content_constants.h"
14
15 namespace {
16
17 // String we will use to convert mime type to plugin type.
18 const char kWindowsMediaPlayerType[] = "application/x-mplayer2";
19 const char kSilverlightTypePrefix[] = "application/x-silverlight";
20 const char kRealPlayerTypePrefix[] = "audio/x-pn-realaudio";
21 const char kJavaTypeSubstring[] = "application/x-java-applet";
22 const char kQuickTimeType[] = "video/quicktime";
23
24 // Arrays containing file extensions connected with specific plugins.
25 // Note: THE ARRAYS MUST BE SORTED BECAUSE BINARY SEARCH IS USED ON THEM!
26 const char* const kWindowsMediaPlayerExtensions[] = {".asx"};
27
28 const char* const kRealPlayerExtensions[] = {".ra", ".ram", ".rm",
29 ".rmm", ".rmp", ".rpm"};
30
31 const char* const kQuickTimeExtensions[] = {".moov", ".mov", ".qif",
32 ".qt", ".qti", ".qtif"};
33
34 } // namespace.
35
36 class UMASenderImpl : public PluginUMAReporter::UMASender {
37 void SendPluginUMA(PluginUMAReporter::ReportType report_type,
38 PluginUMAReporter::PluginType plugin_type) override;
39 };
40
SendPluginUMA(PluginUMAReporter::ReportType report_type,PluginUMAReporter::PluginType plugin_type)41 void UMASenderImpl::SendPluginUMA(PluginUMAReporter::ReportType report_type,
42 PluginUMAReporter::PluginType plugin_type) {
43 // UMA_HISTOGRAM_ENUMERATION requires constant histogram name. Use string
44 // constants explicitly instead of trying to use variables for names.
45 switch (report_type) {
46 case PluginUMAReporter::MISSING_PLUGIN:
47 UMA_HISTOGRAM_ENUMERATION("Plugin.MissingPlugins",
48 plugin_type,
49 PluginUMAReporter::PLUGIN_TYPE_MAX);
50 break;
51 case PluginUMAReporter::DISABLED_PLUGIN:
52 UMA_HISTOGRAM_ENUMERATION("Plugin.DisabledPlugins",
53 plugin_type,
54 PluginUMAReporter::PLUGIN_TYPE_MAX);
55 break;
56 default:
57 NOTREACHED();
58 }
59 }
60
61 // static.
GetInstance()62 PluginUMAReporter* PluginUMAReporter::GetInstance() {
63 return base::Singleton<PluginUMAReporter>::get();
64 }
65
ReportPluginMissing(const std::string & plugin_mime_type,const GURL & plugin_src)66 void PluginUMAReporter::ReportPluginMissing(const std::string& plugin_mime_type,
67 const GURL& plugin_src) {
68 report_sender_->SendPluginUMA(MISSING_PLUGIN,
69 GetPluginType(plugin_mime_type, plugin_src));
70 }
71
ReportPluginDisabled(const std::string & plugin_mime_type,const GURL & plugin_src)72 void PluginUMAReporter::ReportPluginDisabled(
73 const std::string& plugin_mime_type,
74 const GURL& plugin_src) {
75 report_sender_->SendPluginUMA(DISABLED_PLUGIN,
76 GetPluginType(plugin_mime_type, plugin_src));
77 }
78
PluginUMAReporter()79 PluginUMAReporter::PluginUMAReporter() : report_sender_(new UMASenderImpl()) {}
80
~PluginUMAReporter()81 PluginUMAReporter::~PluginUMAReporter() {}
82
83 // static.
CompareCStrings(const char * first,const char * second)84 bool PluginUMAReporter::CompareCStrings(const char* first, const char* second) {
85 return strcmp(first, second) < 0;
86 }
87
CStringArrayContainsCString(const char * const * array,size_t array_size,const char * str)88 bool PluginUMAReporter::CStringArrayContainsCString(const char* const* array,
89 size_t array_size,
90 const char* str) {
91 return std::binary_search(array, array + array_size, str, CompareCStrings);
92 }
93
ExtractFileExtension(const GURL & src,std::string * extension)94 void PluginUMAReporter::ExtractFileExtension(const GURL& src,
95 std::string* extension) {
96 std::string extension_file_path(src.ExtractFileName());
97 if (extension_file_path.empty())
98 extension_file_path = src.host();
99
100 size_t last_dot = extension_file_path.find_last_of('.');
101 if (last_dot != std::string::npos) {
102 *extension = extension_file_path.substr(last_dot);
103 } else {
104 extension->clear();
105 }
106
107 *extension = base::ToLowerASCII(*extension);
108 }
109
GetPluginType(const std::string & plugin_mime_type,const GURL & plugin_src)110 PluginUMAReporter::PluginType PluginUMAReporter::GetPluginType(
111 const std::string& plugin_mime_type,
112 const GURL& plugin_src) {
113 // If we know plugin's mime type, we use it to determine plugin's type. Else,
114 // we try to determine plugin type using plugin source's extension.
115 if (!plugin_mime_type.empty())
116 return MimeTypeToPluginType(base::ToLowerASCII(plugin_mime_type));
117
118 return SrcToPluginType(plugin_src);
119 }
120
SrcToPluginType(const GURL & src)121 PluginUMAReporter::PluginType PluginUMAReporter::SrcToPluginType(
122 const GURL& src) {
123 std::string file_extension;
124 ExtractFileExtension(src, &file_extension);
125 if (CStringArrayContainsCString(kWindowsMediaPlayerExtensions,
126 base::size(kWindowsMediaPlayerExtensions),
127 file_extension.c_str())) {
128 return WINDOWS_MEDIA_PLAYER;
129 }
130
131 if (CStringArrayContainsCString(kQuickTimeExtensions,
132 base::size(kQuickTimeExtensions),
133 file_extension.c_str())) {
134 return QUICKTIME;
135 }
136
137 if (CStringArrayContainsCString(kRealPlayerExtensions,
138 base::size(kRealPlayerExtensions),
139 file_extension.c_str())) {
140 return REALPLAYER;
141 }
142
143 return UNSUPPORTED_EXTENSION;
144 }
145
MimeTypeToPluginType(const std::string & mime_type)146 PluginUMAReporter::PluginType PluginUMAReporter::MimeTypeToPluginType(
147 const std::string& mime_type) {
148 if (mime_type == kWindowsMediaPlayerType)
149 return WINDOWS_MEDIA_PLAYER;
150
151 size_t prefix_length = strlen(kSilverlightTypePrefix);
152 if (strncmp(mime_type.c_str(), kSilverlightTypePrefix, prefix_length) == 0)
153 return SILVERLIGHT;
154
155 prefix_length = strlen(kRealPlayerTypePrefix);
156 if (strncmp(mime_type.c_str(), kRealPlayerTypePrefix, prefix_length) == 0)
157 return REALPLAYER;
158
159 if (strstr(mime_type.c_str(), kJavaTypeSubstring))
160 return JAVA;
161
162 if (mime_type == kQuickTimeType)
163 return QUICKTIME;
164
165 if (mime_type == content::kBrowserPluginMimeType)
166 return BROWSER_PLUGIN;
167
168 return UNSUPPORTED_MIMETYPE;
169 }
170