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