• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsPathHomePageBase(const std::string & path)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 
HasGoogleSearchQueryParam(const std::string & str)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 
LinkDoctorBaseURL()67 GURL LinkDoctorBaseURL() {
68   if (gUseMockLinkDoctorBaseURLForTesting)
69     return GURL("http://mock.linkdoctor.url/for?testing");
70   return GURL(LINKDOCTOR_SERVER_REQUEST_URL);
71 }
72 
SetMockLinkDoctorBaseURLForTesting()73 void SetMockLinkDoctorBaseURLForTesting() {
74   gUseMockLinkDoctorBaseURLForTesting = true;
75 }
76 
AppendGoogleLocaleParam(const GURL & url)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 
StringAppendGoogleLocaleParam(const std::string & url)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 
AppendGoogleTLDParam(Profile * profile,const GURL & url)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 
GetBrand(std::string * brand)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 
GetReactivationBrand(std::string * brand)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 
GetBrand(std::string * brand)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 
GetReactivationBrand(std::string * brand)148 bool GetReactivationBrand(std::string* brand) {
149   brand->clear();
150   return true;
151 }
152 
153 #endif
154 
StartsWithCommandLineGoogleBaseURL(const GURL & url)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 
IsGoogleHostname(const std::string & host,SubdomainPermission subdomain_permission)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 
IsGoogleDomainUrl(const GURL & url,SubdomainPermission subdomain_permission,PortPermission port_permission)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 
IsGoogleHomePageUrl(const GURL & url)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 
IsGoogleSearchUrl(const GURL & url)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 
IsOrganic(const std::string & brand)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 
IsOrganicFirstRun(const std::string & brand)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 
IsInternetCafeBrandCode(const std::string & brand)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 
BrandForTesting(const std::string & brand)285 BrandForTesting::BrandForTesting(const std::string& brand) : brand_(brand) {
286   DCHECK(brand_for_testing == NULL);
287   brand_for_testing = brand_.c_str();
288 }
289 
~BrandForTesting()290 BrandForTesting::~BrandForTesting() {
291   brand_for_testing = NULL;
292 }
293 
294 
295 }  // namespace google_util
296