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.
5 #include "chrome/browser/google/google_util.h"
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/common/net/url_fixer_upper.h"
20 #include "chrome/installer/util/google_update_settings.h"
21 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
22 #include "net/base/url_util.h"
25 #if defined(OS_MACOSX)
26 #include "chrome/browser/mac/keystone_glue.h"
27 #elif defined(OS_CHROMEOS)
28 #include "chrome/browser/google/google_util_chromeos.h"
31 // Only use Link Doctor on official builds. It uses an API key, too, but
32 // seems best to just disable it, for more responsive error pages and to reduce
34 #if defined(GOOGLE_CHROME_BUILD)
35 #define LINKDOCTOR_SERVER_REQUEST_URL "https://www.googleapis.com/rpc"
37 #define LINKDOCTOR_SERVER_REQUEST_URL ""
41 // Helpers --------------------------------------------------------------------
45 const char* brand_for_testing
= NULL
;
46 bool gUseMockLinkDoctorBaseURLForTesting
= false;
48 bool IsPathHomePageBase(const std::string
& path
) {
49 return (path
== "/") || (path
== "/webhp");
55 namespace google_util
{
57 // Global functions -----------------------------------------------------------
59 bool HasGoogleSearchQueryParam(const std::string
& str
) {
60 url_parse::Component
query(0, str
.length()), key
, value
;
61 while (url_parse::ExtractQueryKeyValue(str
.c_str(), &query
, &key
,
63 if ((key
.len
== 1) && (str
[key
.begin
] == 'q') && value
.is_nonempty())
69 GURL
LinkDoctorBaseURL() {
70 if (gUseMockLinkDoctorBaseURLForTesting
)
71 return GURL("http://mock.linkdoctor.url/for?testing");
72 return GURL(LINKDOCTOR_SERVER_REQUEST_URL
);
75 void SetMockLinkDoctorBaseURLForTesting() {
76 gUseMockLinkDoctorBaseURLForTesting
= true;
79 std::string
GetGoogleLocale() {
80 std::string locale
= g_browser_process
->GetApplicationLocale();
81 // Google does not yet recognize 'nb' for Norwegian Bokmal, but it uses
88 GURL
AppendGoogleLocaleParam(const GURL
& url
) {
89 return net::AppendQueryParameter(url
, "hl", GetGoogleLocale());
92 std::string
StringAppendGoogleLocaleParam(const std::string
& url
) {
93 GURL
original_url(url
);
94 DCHECK(original_url
.is_valid());
95 GURL localized_url
= AppendGoogleLocaleParam(original_url
);
96 return localized_url
.spec();
99 std::string
GetGoogleCountryCode(Profile
* profile
) {
100 const std::string google_hostname
=
101 GoogleURLTracker::GoogleURL(profile
).host();
102 const size_t last_dot
= google_hostname
.find_last_of('.');
103 if (last_dot
== std::string::npos
) {
106 std::string country_code
= google_hostname
.substr(last_dot
+ 1);
107 // Assume the com TLD implies the US.
108 if (country_code
== "com")
110 // Google uses the Unicode Common Locale Data Repository (CLDR), and the CLDR
111 // code for the UK is "gb".
112 if (country_code
== "uk")
114 // Catalonia does not have a CLDR country code, since it's a region in Spain,
115 // so use Spain instead.
116 if (country_code
== "cat")
121 GURL
GetGoogleSearchURL(Profile
* profile
) {
122 // The url returned by the tracker does not include the "/search" or the
123 // "q=" query string.
124 std::string search_path
= "search";
125 std::string query_string
= "q=";
126 GURL::Replacements replacements
;
127 replacements
.SetPathStr(search_path
);
128 replacements
.SetQueryStr(query_string
);
129 return GoogleURLTracker::GoogleURL(profile
).ReplaceComponents(replacements
);
134 bool GetBrand(std::string
* brand
) {
135 if (brand_for_testing
) {
136 brand
->assign(brand_for_testing
);
140 base::string16 brand16
;
141 bool ret
= GoogleUpdateSettings::GetBrand(&brand16
);
143 brand
->assign(base::UTF16ToASCII(brand16
));
147 bool GetReactivationBrand(std::string
* brand
) {
148 base::string16 brand16
;
149 bool ret
= GoogleUpdateSettings::GetReactivationBrand(&brand16
);
151 brand
->assign(base::UTF16ToASCII(brand16
));
157 bool GetBrand(std::string
* brand
) {
158 if (brand_for_testing
) {
159 brand
->assign(brand_for_testing
);
163 #if defined(OS_MACOSX)
164 brand
->assign(keystone_glue::BrandCode());
165 #elif defined(OS_CHROMEOS)
166 brand
->assign(google_util::chromeos::GetBrand());
173 bool GetReactivationBrand(std::string
* brand
) {
180 GURL
CommandLineGoogleBaseURL() {
181 // Unit tests may add command-line flags after the first call to this
182 // function, so we don't simply initialize a static |base_url| directly and
183 // then unconditionally return it.
184 CR_DEFINE_STATIC_LOCAL(std::string
, switch_value
, ());
185 CR_DEFINE_STATIC_LOCAL(GURL
, base_url
, ());
186 std::string
current_switch_value(
187 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
188 switches::kGoogleBaseURL
));
189 if (current_switch_value
!= switch_value
) {
190 switch_value
= current_switch_value
;
191 base_url
= URLFixerUpper::FixupURL(switch_value
, std::string());
192 if (!base_url
.is_valid() || base_url
.has_query() || base_url
.has_ref())
198 bool StartsWithCommandLineGoogleBaseURL(const GURL
& url
) {
199 GURL
base_url(CommandLineGoogleBaseURL());
200 return base_url
.is_valid() &&
201 StartsWithASCII(url
.possibly_invalid_spec(), base_url
.spec(), true);
204 bool IsGoogleHostname(const std::string
& host
,
205 SubdomainPermission subdomain_permission
) {
206 GURL
base_url(CommandLineGoogleBaseURL());
207 if (base_url
.is_valid() && (host
== base_url
.host()))
210 size_t tld_length
= net::registry_controlled_domains::GetRegistryLength(
212 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES
,
213 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES
);
214 if ((tld_length
== 0) || (tld_length
== std::string::npos
))
216 std::string
host_minus_tld(host
, 0, host
.length() - tld_length
);
217 if (LowerCaseEqualsASCII(host_minus_tld
, "google."))
219 if (subdomain_permission
== ALLOW_SUBDOMAIN
)
220 return EndsWith(host_minus_tld
, ".google.", false);
221 return LowerCaseEqualsASCII(host_minus_tld
, "www.google.");
224 bool IsGoogleDomainUrl(const GURL
& url
,
225 SubdomainPermission subdomain_permission
,
226 PortPermission port_permission
) {
227 return url
.is_valid() && url
.SchemeIsHTTPOrHTTPS() &&
228 (url
.port().empty() || (port_permission
== ALLOW_NON_STANDARD_PORTS
)) &&
229 google_util::IsGoogleHostname(url
.host(), subdomain_permission
);
232 bool IsGoogleHomePageUrl(const GURL
& url
) {
233 // First check to see if this has a Google domain.
234 if (!IsGoogleDomainUrl(url
, DISALLOW_SUBDOMAIN
, DISALLOW_NON_STANDARD_PORTS
))
237 // Make sure the path is a known home page path.
238 std::string
path(url
.path());
239 return IsPathHomePageBase(path
) || StartsWithASCII(path
, "/ig", false);
242 bool IsGoogleSearchUrl(const GURL
& url
) {
243 // First check to see if this has a Google domain.
244 if (!IsGoogleDomainUrl(url
, DISALLOW_SUBDOMAIN
, DISALLOW_NON_STANDARD_PORTS
))
247 // Make sure the path is a known search path.
248 std::string
path(url
.path());
249 bool is_home_page_base
= IsPathHomePageBase(path
);
250 if (!is_home_page_base
&& (path
!= "/search"))
253 // Check for query parameter in URL parameter and hash fragment, depending on
255 return HasGoogleSearchQueryParam(url
.ref()) ||
256 (!is_home_page_base
&& HasGoogleSearchQueryParam(url
.query()));
259 bool IsOrganic(const std::string
& brand
) {
260 #if defined(OS_MACOSX)
262 // An empty brand string on Mac is used for channels other than stable,
263 // which are always organic.
268 const char* const kBrands
[] = {
269 "CHCA", "CHCB", "CHCG", "CHCH", "CHCI", "CHCJ", "CHCK", "CHCL",
270 "CHFO", "CHFT", "CHHS", "CHHM", "CHMA", "CHMB", "CHME", "CHMF",
271 "CHMG", "CHMH", "CHMI", "CHMQ", "CHMV", "CHNB", "CHNC", "CHNG",
272 "CHNH", "CHNI", "CHOA", "CHOB", "CHOC", "CHON", "CHOO", "CHOP",
273 "CHOQ", "CHOR", "CHOS", "CHOT", "CHOU", "CHOX", "CHOY", "CHOZ",
274 "CHPD", "CHPE", "CHPF", "CHPG", "ECBA", "ECBB", "ECDA", "ECDB",
275 "ECSA", "ECSB", "ECVA", "ECVB", "ECWA", "ECWB", "ECWC", "ECWD",
276 "ECWE", "ECWF", "EUBB", "EUBC", "GGLA", "GGLS"
278 const char* const* end
= &kBrands
[arraysize(kBrands
)];
279 const char* const* found
= std::find(&kBrands
[0], end
, brand
);
283 return StartsWithASCII(brand
, "EUB", true) ||
284 StartsWithASCII(brand
, "EUC", true) ||
285 StartsWithASCII(brand
, "GGR", true);
288 bool IsOrganicFirstRun(const std::string
& brand
) {
289 #if defined(OS_MACOSX)
291 // An empty brand string on Mac is used for channels other than stable,
292 // which are always organic.
297 return StartsWithASCII(brand
, "GG", true) ||
298 StartsWithASCII(brand
, "EU", true);
301 bool IsInternetCafeBrandCode(const std::string
& brand
) {
302 const char* const kBrands
[] = {
303 "CHIQ", "CHSG", "HLJY", "NTMO", "OOBA", "OOBB", "OOBC", "OOBD", "OOBE",
304 "OOBF", "OOBG", "OOBH", "OOBI", "OOBJ", "IDCM",
306 const char* const* end
= &kBrands
[arraysize(kBrands
)];
307 const char* const* found
= std::find(&kBrands
[0], end
, brand
);
312 // BrandForTesting ------------------------------------------------------------
314 BrandForTesting::BrandForTesting(const std::string
& brand
) : brand_(brand
) {
315 DCHECK(brand_for_testing
== NULL
);
316 brand_for_testing
= brand_
.c_str();
319 BrandForTesting::~BrandForTesting() {
320 brand_for_testing
= NULL
;
324 } // namespace google_util