1 // Copyright (c) 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 "chrome/browser/google/google_util.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/command_line.h" 11 #include "base/strings/string16.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "chrome/browser/browser_process.h" 17 #include "chrome/browser/google/google_url_tracker.h" 18 #include "chrome/common/chrome_switches.h" 19 #include "chrome/installer/util/google_update_settings.h" 20 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 21 #include "net/base/url_util.h" 22 #include "url/gurl.h" 23 24 #if defined(OS_MACOSX) 25 #include "chrome/browser/mac/keystone_glue.h" 26 #elif defined(OS_CHROMEOS) 27 #include "chrome/browser/google/google_util_chromeos.h" 28 #endif 29 30 #if defined(GOOGLE_CHROME_BUILD) 31 #include "chrome/browser/google/linkdoctor_internal/linkdoctor_internal.h" 32 #endif 33 34 #ifndef LINKDOCTOR_SERVER_REQUEST_URL 35 #define LINKDOCTOR_SERVER_REQUEST_URL std::string() 36 #endif 37 38 39 // Helpers -------------------------------------------------------------------- 40 41 namespace { 42 43 const char* brand_for_testing = NULL; 44 bool gUseMockLinkDoctorBaseURLForTesting = false; 45 46 bool IsPathHomePageBase(const std::string& path) { 47 return (path == "/") || (path == "/webhp"); 48 } 49 50 } // namespace 51 52 53 namespace google_util { 54 55 // Global functions ----------------------------------------------------------- 56 57 bool HasGoogleSearchQueryParam(const std::string& str) { 58 url_parse::Component query(0, str.length()), key, value; 59 while (url_parse::ExtractQueryKeyValue(str.c_str(), &query, &key, 60 &value)) { 61 if ((key.len == 1) && (str[key.begin] == 'q') && value.is_nonempty()) 62 return true; 63 } 64 return false; 65 } 66 67 GURL LinkDoctorBaseURL() { 68 if (gUseMockLinkDoctorBaseURLForTesting) 69 return GURL("http://mock.linkdoctor.url/for?testing"); 70 return GURL(LINKDOCTOR_SERVER_REQUEST_URL); 71 } 72 73 void SetMockLinkDoctorBaseURLForTesting() { 74 gUseMockLinkDoctorBaseURLForTesting = true; 75 } 76 77 GURL AppendGoogleLocaleParam(const GURL& url) { 78 // Google does not yet recognize 'nb' for Norwegian Bokmal, but it uses 79 // 'no' for that. 80 std::string locale = g_browser_process->GetApplicationLocale(); 81 if (locale == "nb") 82 locale = "no"; 83 return net::AppendQueryParameter(url, "hl", locale); 84 } 85 86 std::string StringAppendGoogleLocaleParam(const std::string& url) { 87 GURL original_url(url); 88 DCHECK(original_url.is_valid()); 89 GURL localized_url = AppendGoogleLocaleParam(original_url); 90 return localized_url.spec(); 91 } 92 93 GURL AppendGoogleTLDParam(Profile* profile, const GURL& url) { 94 const std::string google_domain( 95 net::registry_controlled_domains::GetDomainAndRegistry( 96 GoogleURLTracker::GoogleURL(profile), 97 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)); 98 const size_t first_dot = google_domain.find('.'); 99 if (first_dot == std::string::npos) { 100 NOTREACHED(); 101 return url; 102 } 103 return net::AppendQueryParameter(url, "sd", 104 google_domain.substr(first_dot + 1)); 105 } 106 107 #if defined(OS_WIN) 108 109 bool GetBrand(std::string* brand) { 110 if (brand_for_testing) { 111 brand->assign(brand_for_testing); 112 return true; 113 } 114 115 base::string16 brand16; 116 bool ret = GoogleUpdateSettings::GetBrand(&brand16); 117 if (ret) 118 brand->assign(WideToASCII(brand16)); 119 return ret; 120 } 121 122 bool GetReactivationBrand(std::string* brand) { 123 base::string16 brand16; 124 bool ret = GoogleUpdateSettings::GetReactivationBrand(&brand16); 125 if (ret) 126 brand->assign(WideToASCII(brand16)); 127 return ret; 128 } 129 130 #else 131 132 bool GetBrand(std::string* brand) { 133 if (brand_for_testing) { 134 brand->assign(brand_for_testing); 135 return true; 136 } 137 138 #if defined(OS_MACOSX) 139 brand->assign(keystone_glue::BrandCode()); 140 #elif defined(OS_CHROMEOS) 141 brand->assign(google_util::chromeos::GetBrand()); 142 #else 143 brand->clear(); 144 #endif 145 return true; 146 } 147 148 bool GetReactivationBrand(std::string* brand) { 149 brand->clear(); 150 return true; 151 } 152 153 #endif 154 155 bool StartsWithCommandLineGoogleBaseURL(const GURL& url) { 156 const std::string base_url(CommandLine::ForCurrentProcess()-> 157 GetSwitchValueASCII(switches::kGoogleBaseURL)); 158 return !base_url.empty() && 159 StartsWithASCII(url.possibly_invalid_spec(), base_url, true); 160 } 161 162 bool IsGoogleHostname(const std::string& host, 163 SubdomainPermission subdomain_permission) { 164 const std::string base_url(CommandLine::ForCurrentProcess()-> 165 GetSwitchValueASCII(switches::kGoogleBaseURL)); 166 if (!base_url.empty()) { 167 GURL base_gurl(base_url); 168 if (base_gurl.is_valid() && (host == base_gurl.host())) 169 return true; 170 } 171 172 size_t tld_length = net::registry_controlled_domains::GetRegistryLength( 173 host, 174 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, 175 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); 176 if ((tld_length == 0) || (tld_length == std::string::npos)) 177 return false; 178 std::string host_minus_tld(host, 0, host.length() - tld_length); 179 if (LowerCaseEqualsASCII(host_minus_tld, "google.")) 180 return true; 181 if (subdomain_permission == ALLOW_SUBDOMAIN) 182 return EndsWith(host_minus_tld, ".google.", false); 183 return LowerCaseEqualsASCII(host_minus_tld, "www.google."); 184 } 185 186 bool IsGoogleDomainUrl(const GURL& url, 187 SubdomainPermission subdomain_permission, 188 PortPermission port_permission) { 189 return url.is_valid() && url.SchemeIsHTTPOrHTTPS() && 190 (url.port().empty() || (port_permission == ALLOW_NON_STANDARD_PORTS)) && 191 google_util::IsGoogleHostname(url.host(), subdomain_permission); 192 } 193 194 bool IsGoogleHomePageUrl(const GURL& url) { 195 // First check to see if this has a Google domain. 196 if (!IsGoogleDomainUrl(url, DISALLOW_SUBDOMAIN, DISALLOW_NON_STANDARD_PORTS)) 197 return false; 198 199 // Make sure the path is a known home page path. 200 std::string path(url.path()); 201 return IsPathHomePageBase(path) || StartsWithASCII(path, "/ig", false); 202 } 203 204 bool IsGoogleSearchUrl(const GURL& url) { 205 // First check to see if this has a Google domain. 206 if (!IsGoogleDomainUrl(url, DISALLOW_SUBDOMAIN, DISALLOW_NON_STANDARD_PORTS)) 207 return false; 208 209 // Make sure the path is a known search path. 210 std::string path(url.path()); 211 bool is_home_page_base = IsPathHomePageBase(path); 212 if (!is_home_page_base && (path != "/search")) 213 return false; 214 215 // Check for query parameter in URL parameter and hash fragment, depending on 216 // the path type. 217 return HasGoogleSearchQueryParam(url.ref()) || 218 (!is_home_page_base && HasGoogleSearchQueryParam(url.query())); 219 } 220 221 bool IsOrganic(const std::string& brand) { 222 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 223 if (command_line.HasSwitch(switches::kOrganicInstall)) 224 return true; 225 226 #if defined(OS_MACOSX) 227 if (brand.empty()) { 228 // An empty brand string on Mac is used for channels other than stable, 229 // which are always organic. 230 return true; 231 } 232 #endif 233 234 const char* const kBrands[] = { 235 "CHCA", "CHCB", "CHCG", "CHCH", "CHCI", "CHCJ", "CHCK", "CHCL", 236 "CHFO", "CHFT", "CHHS", "CHHM", "CHMA", "CHMB", "CHME", "CHMF", 237 "CHMG", "CHMH", "CHMI", "CHMQ", "CHMV", "CHNB", "CHNC", "CHNG", 238 "CHNH", "CHNI", "CHOA", "CHOB", "CHOC", "CHON", "CHOO", "CHOP", 239 "CHOQ", "CHOR", "CHOS", "CHOT", "CHOU", "CHOX", "CHOY", "CHOZ", 240 "CHPD", "CHPE", "CHPF", "CHPG", "ECBA", "ECBB", "ECDA", "ECDB", 241 "ECSA", "ECSB", "ECVA", "ECVB", "ECWA", "ECWB", "ECWC", "ECWD", 242 "ECWE", "ECWF", "EUBB", "EUBC", "GGLA", "GGLS" 243 }; 244 const char* const* end = &kBrands[arraysize(kBrands)]; 245 const char* const* found = std::find(&kBrands[0], end, brand); 246 if (found != end) 247 return true; 248 249 return StartsWithASCII(brand, "EUB", true) || 250 StartsWithASCII(brand, "EUC", true) || 251 StartsWithASCII(brand, "GGR", true); 252 } 253 254 bool IsOrganicFirstRun(const std::string& brand) { 255 // Used for testing, to force search engine selector to appear. 256 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 257 if (command_line.HasSwitch(switches::kOrganicInstall)) 258 return true; 259 260 #if defined(OS_MACOSX) 261 if (brand.empty()) { 262 // An empty brand string on Mac is used for channels other than stable, 263 // which are always organic. 264 return true; 265 } 266 #endif 267 268 return StartsWithASCII(brand, "GG", true) || 269 StartsWithASCII(brand, "EU", true); 270 } 271 272 bool IsInternetCafeBrandCode(const std::string& brand) { 273 const char* const kBrands[] = { 274 "CHIQ", "CHSG", "HLJY", "NTMO", "OOBA", "OOBB", "OOBC", "OOBD", "OOBE", 275 "OOBF", "OOBG", "OOBH", "OOBI", "OOBJ", "IDCM", 276 }; 277 const char* const* end = &kBrands[arraysize(kBrands)]; 278 const char* const* found = std::find(&kBrands[0], end, brand); 279 return found != end; 280 } 281 282 283 // BrandForTesting ------------------------------------------------------------ 284 285 BrandForTesting::BrandForTesting(const std::string& brand) : brand_(brand) { 286 DCHECK(brand_for_testing == NULL); 287 brand_for_testing = brand_.c_str(); 288 } 289 290 BrandForTesting::~BrandForTesting() { 291 brand_for_testing = NULL; 292 } 293 294 295 } // namespace google_util 296