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