summaryrefslogtreecommitdiffstats
path: root/webkit/user_agent
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 10:01:07 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 10:01:07 +0000
commitf87d7cb4ec8002c3df07e74dc9b31afcf4ad8b7d (patch)
tree51d2b71b54eff946dbceec119d47d23358960f82 /webkit/user_agent
parent5e194bc61b0c8a3072fb4a0d73106717ceba667e (diff)
downloadchromium_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.cc145
-rw-r--r--webkit/user_agent/user_agent.h29
-rw-r--r--webkit/user_agent/user_agent_unittest.cc60
-rw-r--r--webkit/user_agent/user_agent_util.cc182
-rw-r--r--webkit/user_agent/user_agent_util.h38
-rw-r--r--webkit/user_agent/webkit_user_agent.gypi72
-rw-r--r--webkit/user_agent/webkit_user_agent_export.h29
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_