Home | History | Annotate | Download | only in user_agent
      1 // Copyright 2012 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 "webkit/common/user_agent/user_agent.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/logging.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/synchronization/lock.h"
     12 #include "webkit/common/user_agent/user_agent_util.h"
     13 
     14 namespace webkit_glue {
     15 
     16 namespace {
     17 
     18 class UserAgentState {
     19  public:
     20   UserAgentState();
     21   ~UserAgentState();
     22 
     23   void Set(const std::string& user_agent, bool overriding);
     24   const std::string& Get(const GURL& url) const;
     25 
     26  private:
     27   mutable std::string user_agent_;
     28   // The UA string when we're pretending to be Mac Safari or Win Firefox.
     29   mutable std::string user_agent_for_spoofing_hack_;
     30 
     31   mutable bool user_agent_requested_;
     32   bool user_agent_is_overridden_;
     33 
     34   // This object can be accessed from multiple threads, so use a lock around
     35   // accesses to the data members.
     36   mutable base::Lock lock_;
     37 };
     38 
     39 UserAgentState::UserAgentState()
     40     : user_agent_requested_(false),
     41       user_agent_is_overridden_(false) {
     42 }
     43 
     44 UserAgentState::~UserAgentState() {
     45 }
     46 
     47 void UserAgentState::Set(const std::string& user_agent, bool overriding) {
     48   base::AutoLock auto_lock(lock_);
     49   if (user_agent == user_agent_) {
     50     // We allow the user agent to be set multiple times as long as it
     51     // is set to the same value, in order to simplify unit testing
     52     // given g_user_agent is a global.
     53     return;
     54   }
     55   DCHECK(!user_agent.empty());
     56   DCHECK(!user_agent_requested_) << "Setting the user agent after someone has "
     57       "already requested it can result in unexpected behavior.";
     58   user_agent_is_overridden_ = overriding;
     59   user_agent_ = user_agent;
     60 }
     61 
     62 bool IsMicrosoftSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
     63 #if defined(OS_MACOSX) && !defined(OS_IOS)
     64   // The landing page for updating Silverlight gives a confusing experience
     65   // in browsers that Silverlight doesn't officially support; spoof as
     66   // Safari to reduce the chance that users won't complete updates.
     67   // Should be removed if the sniffing is removed: http://crbug.com/88211
     68   if (url.host() == "www.microsoft.com" &&
     69       StartsWithASCII(url.path(), "/getsilverlight", false)) {
     70     return true;
     71   }
     72 #endif
     73   return false;
     74 }
     75 
     76 bool IsYahooSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
     77 #if defined(OS_MACOSX) && !defined(OS_IOS)
     78   if ((url.host() == "downloads.yahoo.co.jp" &&
     79       StartsWithASCII(url.path(), "/docs/silverlight/", true)) ||
     80       url.host() == "gyao.yahoo.co.jp") {
     81     return true;
     82   }
     83 #elif defined(OS_WIN)
     84   if (url.host() == "promotion.shopping.yahoo.co.jp") {
     85     return true;
     86   }
     87 #endif
     88   return false;
     89 }
     90 
     91 const std::string& UserAgentState::Get(const GURL& url) const {
     92   base::AutoLock auto_lock(lock_);
     93   user_agent_requested_ = true;
     94 
     95   DCHECK(!user_agent_.empty());
     96 
     97   // Workarounds for sites that use misguided UA sniffing.
     98   if (!user_agent_is_overridden_) {
     99     if (IsMicrosoftSiteThatNeedsSpoofingForSilverlight(url) ||
    100         IsYahooSiteThatNeedsSpoofingForSilverlight(url)) {
    101       if (user_agent_for_spoofing_hack_.empty()) {
    102 #if defined(OS_MACOSX) && !defined(OS_IOS)
    103         user_agent_for_spoofing_hack_ =
    104             BuildUserAgentFromProduct("Version/5.1.1 Safari/534.51.22");
    105 #elif defined(OS_WIN)
    106         // Pretend to be Firefox. Silverlight doesn't support Win Safari.
    107         base::StringAppendF(
    108             &user_agent_for_spoofing_hack_,
    109             "Mozilla/5.0 (%s) Gecko/20100101 Firefox/8.0",
    110             webkit_glue::BuildOSCpuInfo().c_str());
    111 #endif
    112       }
    113       DCHECK(!user_agent_for_spoofing_hack_.empty());
    114       return user_agent_for_spoofing_hack_;
    115     }
    116   }
    117 
    118   return user_agent_;
    119 }
    120 
    121 base::LazyInstance<UserAgentState> g_user_agent = LAZY_INSTANCE_INITIALIZER;
    122 
    123 }  // namespace
    124 
    125 void SetUserAgent(const std::string& user_agent, bool overriding) {
    126   g_user_agent.Get().Set(user_agent, overriding);
    127 }
    128 
    129 const std::string& GetUserAgent(const GURL& url) {
    130   return g_user_agent.Get().Get(url);
    131 }
    132 
    133 }  // namespace webkit_glue
    134