diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-10 10:01:07 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-10 10:01:07 +0000 |
commit | f87d7cb4ec8002c3df07e74dc9b31afcf4ad8b7d (patch) | |
tree | 51d2b71b54eff946dbceec119d47d23358960f82 /webkit/user_agent | |
parent | 5e194bc61b0c8a3072fb4a0d73106717ceba667e (diff) | |
download | chromium_src-f87d7cb4ec8002c3df07e74dc9b31afcf4ad8b7d.zip chromium_src-f87d7cb4ec8002c3df07e74dc9b31afcf4ad8b7d.tar.gz chromium_src-f87d7cb4ec8002c3df07e74dc9b31afcf4ad8b7d.tar.bz2 |
Split user agent code out of the 'glue' target
This creates a new user_agent component target for the user agent handling code. This makes it straightforward for iOS to build only the user-agent part of glue. It should also make incremental dismantling of webkit/ easier, since the dependencies on user agent code are now explicit.
The code that was in user_agent.cc/h (the webkit_user_agent target) has been moved to user_agent_util.cc/h, and folded into the user_agent component target. All user-agent related code has been moved to a new webkit/user_agent/ directory.
BUG=None
Review URL: https://chromiumcodereview.appspot.com/10869073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155695 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/user_agent')
-rw-r--r-- | webkit/user_agent/user_agent.cc | 145 | ||||
-rw-r--r-- | webkit/user_agent/user_agent.h | 29 | ||||
-rw-r--r-- | webkit/user_agent/user_agent_unittest.cc | 60 | ||||
-rw-r--r-- | webkit/user_agent/user_agent_util.cc | 182 | ||||
-rw-r--r-- | webkit/user_agent/user_agent_util.h | 38 | ||||
-rw-r--r-- | webkit/user_agent/webkit_user_agent.gypi | 72 | ||||
-rw-r--r-- | webkit/user_agent/webkit_user_agent_export.h | 29 |
7 files changed, 555 insertions, 0 deletions
diff --git a/webkit/user_agent/user_agent.cc b/webkit/user_agent/user_agent.cc new file mode 100644 index 0000000..0efdb22 --- /dev/null +++ b/webkit/user_agent/user_agent.cc @@ -0,0 +1,145 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/user_agent/user_agent.h" + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/synchronization/lock.h" +#include "webkit/user_agent/user_agent_util.h" + +namespace webkit_glue { + +namespace { + +class UserAgentState { + public: + UserAgentState(); + ~UserAgentState(); + + void Set(const std::string& user_agent, bool overriding); + const std::string& Get(const GURL& url) const; + + private: + mutable std::string user_agent_; + // The UA string when we're pretending to be Mac Safari or Win Firefox. + mutable std::string user_agent_for_spoofing_hack_; + + mutable bool user_agent_requested_; + bool user_agent_is_overridden_; + + // This object can be accessed from multiple threads, so use a lock around + // accesses to the data members. + mutable base::Lock lock_; +}; + +UserAgentState::UserAgentState() + : user_agent_requested_(false), + user_agent_is_overridden_(false) { +} + +UserAgentState::~UserAgentState() { +} + +void UserAgentState::Set(const std::string& user_agent, bool overriding) { + base::AutoLock auto_lock(lock_); + if (user_agent == user_agent_) { + // We allow the user agent to be set multiple times as long as it + // is set to the same value, in order to simplify unit testing + // given g_user_agent is a global. + return; + } + DCHECK(!user_agent.empty()); + DCHECK(!user_agent_requested_) << "Setting the user agent after someone has " + "already requested it can result in unexpected behavior."; + user_agent_is_overridden_ = overriding; + user_agent_ = user_agent; +} + +bool IsMicrosoftSiteThatNeedsSpoofingForSilverlight(const GURL& url) { +#if defined(OS_MACOSX) + // The landing page for updating Silverlight gives a confusing experience + // in browsers that Silverlight doesn't officially support; spoof as + // Safari to reduce the chance that users won't complete updates. + // Should be removed if the sniffing is removed: http://crbug.com/88211 + if (url.host() == "www.microsoft.com" && + StartsWithASCII(url.path(), "/getsilverlight", false)) { + return true; + } +#endif + return false; +} + +bool IsYahooSiteThatNeedsSpoofingForSilverlight(const GURL& url) { +#if defined(OS_MACOSX) || defined(OS_WIN) + // The following Yahoo! JAPAN pages erroneously judge that Silverlight does + // not support Chromium. Until the pages are fixed, spoof the UA. + // http://crbug.com/104426 + if (url.host() == "headlines.yahoo.co.jp" && + StartsWithASCII(url.path(), "/videonews/", true)) { + return true; + } +#endif +#if defined(OS_MACOSX) + if ((url.host() == "downloads.yahoo.co.jp" && + StartsWithASCII(url.path(), "/docs/silverlight/", true)) || + url.host() == "gyao.yahoo.co.jp") { + return true; + } +#elif defined(OS_WIN) + if ((url.host() == "weather.yahoo.co.jp" && + StartsWithASCII(url.path(), "/weather/zoomradar/", true)) || + url.host() == "promotion.shopping.yahoo.co.jp" || + url.host() == "pokemon.kids.yahoo.co.jp") { + return true; + } +#endif + return false; +} + +const std::string& UserAgentState::Get(const GURL& url) const { + base::AutoLock auto_lock(lock_); + user_agent_requested_ = true; + + DCHECK(!user_agent_.empty()); + + // Workarounds for sites that use misguided UA sniffing. + if (!user_agent_is_overridden_) { + if (IsMicrosoftSiteThatNeedsSpoofingForSilverlight(url) || + IsYahooSiteThatNeedsSpoofingForSilverlight(url)) { + if (user_agent_for_spoofing_hack_.empty()) { +#if defined(OS_MACOSX) + user_agent_for_spoofing_hack_ = + BuildUserAgentFromProduct("Version/5.1.1 Safari/534.51.22"); +#elif defined(OS_WIN) + // Pretend to be Firefox. Silverlight doesn't support Win Safari. + base::StringAppendF( + &user_agent_for_spoofing_hack_, + "Mozilla/5.0 (%s) Gecko/20100101 Firefox/8.0", + webkit_glue::BuildOSCpuInfo().c_str()); +#endif + } + DCHECK(!user_agent_for_spoofing_hack_.empty()); + return user_agent_for_spoofing_hack_; + } + } + + return user_agent_; +} + +base::LazyInstance<UserAgentState> g_user_agent = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +void SetUserAgent(const std::string& user_agent, bool overriding) { + g_user_agent.Get().Set(user_agent, overriding); +} + +const std::string& GetUserAgent(const GURL& url) { + return g_user_agent.Get().Get(url); +} + +} // namespace webkit_glue diff --git a/webkit/user_agent/user_agent.h b/webkit/user_agent/user_agent.h new file mode 100644 index 0000000..833882f --- /dev/null +++ b/webkit/user_agent/user_agent.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_USER_AGENT_USER_AGENT_H_ +#define WEBKIT_USER_AGENT_USER_AGENT_H_ + +#include <string> + +#include "base/basictypes.h" +#include "googleurl/src/gurl.h" +#include "webkit/user_agent/webkit_user_agent_export.h" + +namespace webkit_glue { + +// Sets the user agent. Pass true for overriding if this is a custom +// user agent instead of the default one (in order to turn off any browser +// sniffing workarounds). This must be called before GetUserAgent() can +// be called. +WEBKIT_USER_AGENT_EXPORT void SetUserAgent(const std::string& user_agent, + bool overriding); + +// Returns the user agent to use for the given URL. SetUserAgent() must +// be called prior to calling this function. +WEBKIT_USER_AGENT_EXPORT const std::string& GetUserAgent(const GURL& url); + +} // namespace webkit_glue + +#endif // WEBKIT_USER_AGENT_USER_AGENT_H_ diff --git a/webkit/user_agent/user_agent_unittest.cc b/webkit/user_agent/user_agent_unittest.cc new file mode 100644 index 0000000..9a6058d --- /dev/null +++ b/webkit/user_agent/user_agent_unittest.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/user_agent/user_agent.h" + +#include <string> + +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/tools/test_shell/test_shell_test.h" + +namespace { + +class WebkitGlueUserAgentTest : public TestShellTest { +}; + +bool IsSpoofedUserAgent(const std::string& user_agent) { + return user_agent.find("TestShell") == std::string::npos; +} + +TEST_F(WebkitGlueUserAgentTest, UserAgentSpoofingHack) { + enum Platform { + NONE = 0, + MACOSX = 1, + WIN = 2, + OTHER = 4, + }; + + struct Expected { + const char* url; + int os_mask; + }; + + Expected expected[] = { + { "http://wwww.google.com", NONE }, + { "http://www.microsoft.com/getsilverlight", MACOSX }, + { "http://headlines.yahoo.co.jp/videonews/", MACOSX | WIN }, + { "http://downloads.yahoo.co.jp/docs/silverlight/", MACOSX }, + { "http://gyao.yahoo.co.jp/", MACOSX }, + { "http://weather.yahoo.co.jp/weather/zoomradar/", WIN }, + { "http://promotion.shopping.yahoo.co.jp/", WIN }, + { "http://pokemon.kids.yahoo.co.jp", WIN }, + }; +#if defined(OS_MACOSX) + int os_bit = MACOSX; +#elif defined(OS_WIN) + int os_bit = WIN; +#else + int os_bit = OTHER; +#endif + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { + EXPECT_EQ((expected[i].os_mask & os_bit) != 0, + IsSpoofedUserAgent( + webkit_glue::GetUserAgent(GURL(expected[i].url)))); + } +} + +} // namespace diff --git a/webkit/user_agent/user_agent_util.cc b/webkit/user_agent/user_agent_util.cc new file mode 100644 index 0000000..a30fa87 --- /dev/null +++ b/webkit/user_agent/user_agent_util.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/user_agent/user_agent_util.h" + +#if defined(OS_POSIX) && !defined(OS_MACOSX) +#include <sys/utsname.h> +#endif + +#include "base/lazy_instance.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/sys_info.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif + +// Generated +#include "webkit_version.h" // NOLINT + +namespace webkit_glue { + +std::string GetWebKitVersion() { + return base::StringPrintf("%d.%d (%s)", + WEBKIT_VERSION_MAJOR, + WEBKIT_VERSION_MINOR, + WEBKIT_SVN_REVISION); +} + +std::string GetWebKitRevision() { + return WEBKIT_SVN_REVISION; +} + +std::string BuildOSCpuInfo() { + std::string os_cpu; + +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) ||\ + defined(OS_ANDROID) + int32 os_major_version = 0; + int32 os_minor_version = 0; + int32 os_bugfix_version = 0; + base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, + &os_minor_version, + &os_bugfix_version); +#endif + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) + // Should work on any Posix system. + struct utsname unixinfo; + uname(&unixinfo); + + std::string cputype; + // special case for biarch systems + if (strcmp(unixinfo.machine, "x86_64") == 0 && + sizeof(void*) == sizeof(int32)) { // NOLINT + cputype.assign("i686 (x86_64)"); + } else { + cputype.assign(unixinfo.machine); + } +#endif + +#if defined(OS_WIN) + std::string architecture_token; + base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); + if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) { + architecture_token = "; WOW64"; + } else { + base::win::OSInfo::WindowsArchitecture windows_architecture = + os_info->architecture(); + if (windows_architecture == base::win::OSInfo::X64_ARCHITECTURE) + architecture_token = "; Win64; x64"; + else if (windows_architecture == base::win::OSInfo::IA64_ARCHITECTURE) + architecture_token = "; Win64; IA64"; + } +#endif + +#if defined(OS_ANDROID) + std::string android_info_str; + + // Send information about the device. + bool semicolon_inserted = false; + std::string android_build_codename = base::SysInfo::GetAndroidBuildCodename(); + std::string android_device_name = base::SysInfo::GetDeviceName(); + if ("REL" == android_build_codename && android_device_name.size() > 0) { + android_info_str += "; " + android_device_name; + semicolon_inserted = true; + } + + // Append the build ID. + std::string android_build_id = base::SysInfo::GetAndroidBuildID(); + if (android_build_id.size() > 0) { + if (!semicolon_inserted) { + android_info_str += ";"; + } + android_info_str += " Build/" + android_build_id; + } +#endif + + base::StringAppendF( + &os_cpu, +#if defined(OS_WIN) + "Windows NT %d.%d%s", + os_major_version, + os_minor_version, + architecture_token.c_str() +#elif defined(OS_MACOSX) + "Intel Mac OS X %d_%d_%d", + os_major_version, + os_minor_version, + os_bugfix_version +#elif defined(OS_CHROMEOS) + "CrOS " + "%s %d.%d.%d", + cputype.c_str(), // e.g. i686 + os_major_version, + os_minor_version, + os_bugfix_version +#elif defined(OS_ANDROID) + "Android %d.%d.%d%s", + os_major_version, + os_minor_version, + os_bugfix_version, + android_info_str.c_str() +#else + "%s %s", + unixinfo.sysname, // e.g. Linux + cputype.c_str() // e.g. i686 +#endif + ); // NOLINT + + return os_cpu; +} + +int GetWebKitMajorVersion() { + return WEBKIT_VERSION_MAJOR; +} + +int GetWebKitMinorVersion() { + return WEBKIT_VERSION_MINOR; +} + +std::string BuildUserAgentFromProduct(const std::string& product) { + const char kUserAgentPlatform[] = +#if defined(OS_WIN) + ""; +#elif defined(OS_MACOSX) + "Macintosh; "; +#elif defined(USE_X11) + "X11; "; // strange, but that's what Firefox uses +#elif defined(OS_ANDROID) + "Linux; "; +#else + "Unknown; "; +#endif + + std::string os_info; + base::StringAppendF(&os_info, "%s%s", kUserAgentPlatform, + webkit_glue::BuildOSCpuInfo().c_str()); + return BuildUserAgentFromOSAndProduct(os_info, product); +} + +std::string BuildUserAgentFromOSAndProduct(const std::string& os_info, + const std::string& product) { + // Derived from Safari's UA string. + // This is done to expose our product name in a manner that is maximally + // compatible with Safari, we hope!! + std::string user_agent; + base::StringAppendF( + &user_agent, + "Mozilla/5.0 (%s) AppleWebKit/%d.%d (KHTML, like Gecko) %s Safari/%d.%d", + os_info.c_str(), + WEBKIT_VERSION_MAJOR, + WEBKIT_VERSION_MINOR, + product.c_str(), + WEBKIT_VERSION_MAJOR, + WEBKIT_VERSION_MINOR); + return user_agent; +} + +} // namespace webkit_glue diff --git a/webkit/user_agent/user_agent_util.h b/webkit/user_agent/user_agent_util.h new file mode 100644 index 0000000..dc28130 --- /dev/null +++ b/webkit/user_agent/user_agent_util.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_USER_AGENT_USER_AGENT_UTIL_H_ +#define WEBKIT_USER_AGENT_USER_AGENT_UTIL_H_ + +#include <string> + +#include "base/basictypes.h" +#include "webkit/user_agent/webkit_user_agent_export.h" + +namespace webkit_glue { + +// Builds a User-agent compatible string that describes the OS and CPU type. +WEBKIT_USER_AGENT_EXPORT std::string BuildOSCpuInfo(); + +// Returns the WebKit version, in the form "major.minor (branch@revision)". +WEBKIT_USER_AGENT_EXPORT std::string GetWebKitVersion(); + +// The following 2 functions return the major and minor webkit versions. +WEBKIT_USER_AGENT_EXPORT int GetWebKitMajorVersion(); +WEBKIT_USER_AGENT_EXPORT int GetWebKitMinorVersion(); + +// Helper function to generate a full user agent string from a short +// product name. +WEBKIT_USER_AGENT_EXPORT std::string BuildUserAgentFromProduct( + const std::string& product); + +// Builds a full user agent string given a string describing the OS and a +// product name. +WEBKIT_USER_AGENT_EXPORT std::string BuildUserAgentFromOSAndProduct( + const std::string& os_info, + const std::string& product); + +} // namespace webkit_glue + +#endif // WEBKIT_USER_AGENT_USER_AGENT_UTIL_H_ diff --git a/webkit/user_agent/webkit_user_agent.gypi b/webkit/user_agent/webkit_user_agent.gypi new file mode 100644 index 0000000..06bef84 --- /dev/null +++ b/webkit/user_agent/webkit_user_agent.gypi @@ -0,0 +1,72 @@ +# Copyright 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'conditions': [ + ['inside_chromium_build==0', { + 'webkit_src_dir': '../../../../..', + },{ + 'webkit_src_dir': '../../third_party/WebKit', + }], + ], + }, + 'targets': [ + { + 'target_name': 'webkit_version', + 'type': 'none', + 'actions': [ + { + 'action_name': 'webkit_version', + 'inputs': [ + '<(script)', + '<(webkit_src_dir)<(version_file)', + '../../build/util/lastchange.py', # Used by the script. + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/webkit_version.h', + ], + 'action': ['python', '<(script)', '<(webkit_src_dir)', + '<(version_file)', '<(SHARED_INTERMEDIATE_DIR)'], + 'variables': { + 'script': '../build/webkit_version.py', + # version_file is a relative path from |webkit_src_dir| to + # the version file. But gyp will eat the variable unless + # it looks like an absolute path, so write it like one and + # then use it carefully above. + 'version_file': '/Source/WebCore/Configurations/Version.xcconfig', + }, + }, + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(SHARED_INTERMEDIATE_DIR)', + ], + }, + # Dependents may rely on files generated by this target or one of its + # own hard dependencies. + 'hard_dependency': 1, + }, + { + 'target_name': 'user_agent', + 'type': '<(component)', + 'defines': [ + 'WEBKIT_USER_AGENT_IMPLEMENTATION', + ], + 'dependencies': [ + 'webkit_version', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:base_i18n', + '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + ], + 'sources': [ + 'user_agent.cc', + 'user_agent.h', + 'user_agent_util.cc', + 'user_agent_util.h', + 'webkit_user_agent_export.h', + ], + }, + ], +} diff --git a/webkit/user_agent/webkit_user_agent_export.h b/webkit/user_agent/webkit_user_agent_export.h new file mode 100644 index 0000000..d72c9f3 --- /dev/null +++ b/webkit/user_agent/webkit_user_agent_export.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_USER_AGENT_WEBKIT_USER_AGENT_EXPORT_H_ +#define WEBKIT_USER_AGENT_WEBKIT_USER_AGENT_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(WEBKIT_USER_AGENT_IMPLEMENTATION) +#define WEBKIT_USER_AGENT_EXPORT __declspec(dllexport) +#else +#define WEBKIT_USER_AGENT_EXPORT __declspec(dllimport) +#endif // defined(WEBKIT_USER_AGENT_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(WEBKIT_USER_AGENT_IMPLEMENTATION) +#define WEBKIT_USER_AGENT_EXPORT __attribute__((visibility("default"))) +#else +#define WEBKIT_USER_AGENT_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define WEBKIT_USER_AGENT_EXPORT +#endif + +#endif // WEBKIT_USER_AGENT_WEBKIT_USER_AGENT_EXPORT_H_ |