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 "ios/web/public/user_agent.h" 6 7#import <UIKit/UIKit.h> 8 9#include <sys/sysctl.h> 10#include <string> 11 12#include "base/mac/scoped_nsobject.h" 13#include "base/strings/string_util.h" 14#include "base/strings/stringprintf.h" 15#include "base/strings/sys_string_conversions.h" 16#include "base/sys_info.h" 17 18namespace { 19 20struct UAVersions { 21 const char* safari_version_string; 22 const char* webkit_version_string; 23}; 24 25struct OSVersionMap { 26 int32 major_os_version; 27 int32 minor_os_version; 28 UAVersions ua_versions; 29}; 30 31const UAVersions& GetUAVersionsForCurrentOS() { 32 // The WebKit version can be extracted dynamically from UIWebView, but the 33 // Safari version can't be, so a lookup table is used instead (for both, since 34 // the reported versions should stay in sync). 35 static const OSVersionMap version_map[] = { 36 { 8, 0, { "600.1.4", "600.1.4" } }, 37 { 7, 1, { "9537.53", "537.51.2" } }, 38 { 7, 0, { "9537.53", "537.51.1" } }, 39 // 6.1 has the same values as 6.0. 40 { 6, 0, { "8536.25", "536.26" } }, 41 }; 42 43 int32 os_major_version = 0; 44 int32 os_minor_version = 0; 45 int32 os_bugfix_version = 0; 46 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, 47 &os_minor_version, 48 &os_bugfix_version); 49 50 // Return the versions corresponding to the first (and thus highest) OS 51 // version less than or equal to the given OS version. 52 for (unsigned int i = 0; i < arraysize(version_map); ++i) { 53 if (os_major_version > version_map[i].major_os_version || 54 (os_major_version == version_map[i].major_os_version && 55 os_minor_version >= version_map[i].minor_os_version)) 56 return version_map[i].ua_versions; 57 } 58 NOTREACHED(); 59 return version_map[arraysize(version_map) - 1].ua_versions; 60} 61 62std::string BuildOSCpuInfo() { 63 int32 os_major_version = 0; 64 int32 os_minor_version = 0; 65 int32 os_bugfix_version = 0; 66 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, 67 &os_minor_version, 68 &os_bugfix_version); 69 std::string os_version; 70 if (os_bugfix_version == 0) { 71 base::StringAppendF(&os_version, 72 "%d_%d", 73 os_major_version, 74 os_minor_version); 75 } else { 76 base::StringAppendF(&os_version, 77 "%d_%d_%d", 78 os_major_version, 79 os_minor_version, 80 os_bugfix_version); 81 } 82 83 // Remove the end of the platform name. For example "iPod touch" becomes 84 // "iPod". 85 std::string platform = base::SysNSStringToUTF8( 86 [[UIDevice currentDevice] model]); 87 size_t position = platform.find_first_of(" "); 88 if (position != std::string::npos) 89 platform = platform.substr(0, position); 90 91 std::string os_cpu; 92 base::StringAppendF( 93 &os_cpu, 94 "%s; CPU %s %s like Mac OS X", 95 platform.c_str(), 96 (platform == "iPad") ? "OS" : "iPhone OS", 97 os_version.c_str()); 98 99 return os_cpu; 100} 101 102} // namespace 103 104namespace web { 105 106std::string BuildUserAgentFromProduct(const std::string& product) { 107 // Retrieve the kernel build number. 108 int mib[2] = {CTL_KERN, KERN_OSVERSION}; 109 unsigned int namelen = sizeof(mib) / sizeof(mib[0]); 110 size_t bufferSize = 0; 111 sysctl(mib, namelen, NULL, &bufferSize, NULL, 0); 112 char kernel_version[bufferSize]; 113 int result = sysctl(mib, namelen, kernel_version, &bufferSize, NULL, 0); 114 DCHECK(result == 0); 115 116 UAVersions ua_versions = GetUAVersionsForCurrentOS(); 117 118 std::string user_agent; 119 base::StringAppendF(&user_agent, 120 "Mozilla/5.0 (%s) AppleWebKit/%s" 121 " (KHTML, like Gecko) %s Mobile/%s Safari/%s", 122 BuildOSCpuInfo().c_str(), 123 ua_versions.webkit_version_string, 124 product.c_str(), 125 kernel_version, 126 ua_versions.safari_version_string); 127 128 return user_agent; 129} 130 131} // namespace web 132