1// Copyright 2014 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/public/common/user_agent.h"
6
7#include "base/logging.h"
8#include "base/strings/string_util.h"
9#include "base/strings/stringprintf.h"
10#include "base/sys_info.h"
11#include "build/build_config.h"
12
13#if defined(OS_POSIX) && !defined(OS_MACOSX)
14#include <sys/utsname.h>
15#endif
16
17#if defined(OS_WIN)
18#include "base/win/windows_version.h"
19#endif
20
21// Generated
22#include "webkit_version.h"  // NOLINT
23
24namespace content {
25
26namespace {
27
28#if defined(OS_ANDROID)
29std::string GetAndroidDeviceName() {
30  return base::SysInfo::GetDeviceName();
31}
32#endif
33
34}  // namespace
35
36std::string GetWebKitVersion() {
37  return base::StringPrintf("%d.%d (%s)",
38                            WEBKIT_VERSION_MAJOR,
39                            WEBKIT_VERSION_MINOR,
40                            WEBKIT_SVN_REVISION);
41}
42
43int GetWebKitMajorVersion() {
44  return WEBKIT_VERSION_MAJOR;
45}
46
47int GetWebKitMinorVersion() {
48  return WEBKIT_VERSION_MINOR;
49}
50
51std::string GetWebKitRevision() {
52  return WEBKIT_SVN_REVISION;
53}
54
55std::string BuildOSCpuInfo() {
56  std::string os_cpu;
57
58#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) ||\
59    defined(OS_ANDROID)
60  int32 os_major_version = 0;
61  int32 os_minor_version = 0;
62  int32 os_bugfix_version = 0;
63  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
64                                               &os_minor_version,
65                                               &os_bugfix_version);
66#endif
67
68#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
69  // Should work on any Posix system.
70  struct utsname unixinfo;
71  uname(&unixinfo);
72
73  std::string cputype;
74  // special case for biarch systems
75  if (strcmp(unixinfo.machine, "x86_64") == 0 &&
76      sizeof(void*) == sizeof(int32)) {  // NOLINT
77    cputype.assign("i686 (x86_64)");
78  } else {
79    cputype.assign(unixinfo.machine);
80  }
81#endif
82
83#if defined(OS_WIN)
84  std::string architecture_token;
85  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
86  if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
87    architecture_token = "; WOW64";
88  } else {
89    base::win::OSInfo::WindowsArchitecture windows_architecture =
90        os_info->architecture();
91    if (windows_architecture == base::win::OSInfo::X64_ARCHITECTURE)
92      architecture_token = "; Win64; x64";
93    else if (windows_architecture == base::win::OSInfo::IA64_ARCHITECTURE)
94      architecture_token = "; Win64; IA64";
95  }
96#endif
97
98#if defined(OS_ANDROID)
99  std::string android_version_str;
100  base::StringAppendF(
101      &android_version_str, "%d.%d", os_major_version, os_minor_version);
102  if (os_bugfix_version != 0)
103    base::StringAppendF(&android_version_str, ".%d", os_bugfix_version);
104
105  std::string android_info_str;
106
107  // Send information about the device.
108  bool semicolon_inserted = false;
109  std::string android_build_codename = base::SysInfo::GetAndroidBuildCodename();
110  std::string android_device_name = GetAndroidDeviceName();
111  if ("REL" == android_build_codename && android_device_name.size() > 0) {
112    android_info_str += "; " + android_device_name;
113    semicolon_inserted = true;
114  }
115
116  // Append the build ID.
117  std::string android_build_id = base::SysInfo::GetAndroidBuildID();
118  if (android_build_id.size() > 0) {
119    if (!semicolon_inserted) {
120      android_info_str += ";";
121    }
122    android_info_str += " Build/" + android_build_id;
123  }
124#endif
125
126  base::StringAppendF(
127      &os_cpu,
128#if defined(OS_WIN)
129      "Windows NT %d.%d%s",
130      os_major_version,
131      os_minor_version,
132      architecture_token.c_str()
133#elif defined(OS_MACOSX)
134      "Intel Mac OS X %d_%d_%d",
135      os_major_version,
136      os_minor_version,
137      os_bugfix_version
138#elif defined(OS_CHROMEOS)
139      "CrOS "
140      "%s %d.%d.%d",
141      cputype.c_str(),   // e.g. i686
142      os_major_version,
143      os_minor_version,
144      os_bugfix_version
145#elif defined(OS_ANDROID)
146      "Android %s%s",
147      android_version_str.c_str(),
148      android_info_str.c_str()
149#else
150      "%s %s",
151      unixinfo.sysname,  // e.g. Linux
152      cputype.c_str()    // e.g. i686
153#endif
154  );  // NOLINT
155
156  return os_cpu;
157}
158
159std::string BuildUserAgentFromProduct(const std::string& product) {
160  const char kUserAgentPlatform[] =
161#if defined(OS_WIN)
162      "";
163#elif defined(OS_MACOSX)
164      "Macintosh; ";
165#elif defined(USE_X11) || defined(USE_OZONE)
166      "X11; ";           // strange, but that's what Firefox uses
167#elif defined(OS_ANDROID)
168      "Linux; ";
169#else
170      "Unknown; ";
171#endif
172
173  std::string os_info;
174  base::StringAppendF(
175      &os_info, "%s%s", kUserAgentPlatform, BuildOSCpuInfo().c_str());
176  return BuildUserAgentFromOSAndProduct(os_info, product);
177}
178
179std::string BuildUserAgentFromOSAndProduct(const std::string& os_info,
180                                           const std::string& product) {
181  // Derived from Safari's UA string.
182  // This is done to expose our product name in a manner that is maximally
183  // compatible with Safari, we hope!!
184  std::string user_agent;
185  base::StringAppendF(
186      &user_agent,
187      "Mozilla/5.0 (%s) AppleWebKit/%d.%d (KHTML, like Gecko) %s Safari/%d.%d",
188      os_info.c_str(),
189      WEBKIT_VERSION_MAJOR,
190      WEBKIT_VERSION_MINOR,
191      product.c_str(),
192      WEBKIT_VERSION_MAJOR,
193      WEBKIT_VERSION_MINOR);
194  return user_agent;
195}
196
197}  // namespace content
198