OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/search/local_ntp_source.h" | 5 #include "chrome/browser/search/local_ntp_source.h" |
6 | 6 |
7 #include <stddef.h> | |
8 | |
9 #include "base/base64.h" | 7 #include "base/base64.h" |
10 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/feature_list.h" |
11 #include "base/json/json_string_value_serializer.h" | 10 #include "base/json/json_string_value_serializer.h" |
| 11 #include "base/json/json_writer.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/memory/ref_counted_memory.h" | 14 #include "base/memory/ref_counted_memory.h" |
15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/values.h" | 17 #include "base/values.h" |
18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 19 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/browser/search/instant_io_context.h" | 20 #include "chrome/browser/search/instant_io_context.h" |
20 #include "chrome/browser/search/local_files_ntp_source.h" | 21 #include "chrome/browser/search/local_files_ntp_source.h" |
| 22 #include "chrome/browser/search/one_google_bar/one_google_bar_data.h" |
| 23 #include "chrome/browser/search/one_google_bar/one_google_bar_service.h" |
| 24 #include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h" |
21 #include "chrome/browser/search_engines/template_url_service_factory.h" | 25 #include "chrome/browser/search_engines/template_url_service_factory.h" |
22 #include "chrome/browser/themes/theme_properties.h" | 26 #include "chrome/browser/themes/theme_properties.h" |
23 #include "chrome/browser/themes/theme_service.h" | 27 #include "chrome/browser/themes/theme_service.h" |
24 #include "chrome/browser/themes/theme_service_factory.h" | 28 #include "chrome/browser/themes/theme_service_factory.h" |
25 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
26 #include "chrome/common/url_constants.h" | 30 #include "chrome/common/url_constants.h" |
27 #include "chrome/grit/browser_resources.h" | 31 #include "chrome/grit/browser_resources.h" |
28 #include "chrome/grit/generated_resources.h" | 32 #include "chrome/grit/generated_resources.h" |
29 #include "chrome/grit/theme_resources.h" | 33 #include "chrome/grit/theme_resources.h" |
30 #include "components/search_engines/template_url_service.h" | 34 #include "components/search_engines/template_url_service.h" |
31 #include "components/search_engines/template_url_service_observer.h" | 35 #include "components/search_engines/template_url_service_observer.h" |
32 #include "components/strings/grit/components_strings.h" | 36 #include "components/strings/grit/components_strings.h" |
33 #include "content/public/browser/browser_thread.h" | 37 #include "content/public/browser/browser_thread.h" |
34 #include "crypto/secure_hash.h" | 38 #include "crypto/secure_hash.h" |
35 #include "net/base/hash_value.h" | 39 #include "net/base/hash_value.h" |
36 #include "net/url_request/url_request.h" | 40 #include "net/url_request/url_request.h" |
37 #include "third_party/skia/include/core/SkColor.h" | 41 #include "third_party/skia/include/core/SkColor.h" |
38 #include "ui/base/l10n/l10n_util.h" | 42 #include "ui/base/l10n/l10n_util.h" |
39 #include "ui/base/resource/resource_bundle.h" | 43 #include "ui/base/resource/resource_bundle.h" |
40 #include "ui/base/webui/web_ui_util.h" | 44 #include "ui/base/webui/web_ui_util.h" |
41 #include "ui/resources/grit/ui_resources.h" | 45 #include "ui/resources/grit/ui_resources.h" |
42 #include "url/gurl.h" | 46 #include "url/gurl.h" |
43 | 47 |
44 namespace { | 48 namespace { |
45 | 49 |
| 50 base::Feature kOneGoogleBarOnLocalNtpFeature{"OneGoogleBarOnLocalNtp", |
| 51 base::FEATURE_DISABLED_BY_DEFAULT}; |
| 52 |
46 // Signifies a locally constructed resource, i.e. not from grit/. | 53 // Signifies a locally constructed resource, i.e. not from grit/. |
47 const int kLocalResource = -1; | 54 const int kLocalResource = -1; |
48 | 55 |
49 const char kConfigDataFilename[] = "config.js"; | 56 const char kConfigDataFilename[] = "config.js"; |
50 const char kThemeCSSFilename[] = "theme.css"; | 57 const char kThemeCSSFilename[] = "theme.css"; |
51 const char kMainHtmlFilename[] = "local-ntp.html"; | 58 const char kMainHtmlFilename[] = "local-ntp.html"; |
| 59 const char kOneGoogleBarScriptFilename[] = "one-google.js"; |
| 60 const char kOneGoogleBarInHeadStyleFilename[] = "one-google/in-head.css"; |
| 61 const char kOneGoogleBarInHeadScriptFilename[] = "one-google/in-head.js"; |
| 62 const char kOneGoogleBarAfterBarScriptFilename[] = "one-google/after-bar.js"; |
| 63 const char kOneGoogleBarEndOfBodyScriptFilename[] = "one-google/end-of-body.js"; |
52 | 64 |
53 const struct Resource{ | 65 const struct Resource{ |
54 const char* filename; | 66 const char* filename; |
55 int identifier; | 67 int identifier; |
56 const char* mime_type; | 68 const char* mime_type; |
57 } kResources[] = { | 69 } kResources[] = { |
58 {kMainHtmlFilename, kLocalResource, "text/html"}, | 70 {kMainHtmlFilename, kLocalResource, "text/html"}, |
59 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"}, | 71 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"}, |
60 {kConfigDataFilename, kLocalResource, "application/javascript"}, | 72 {kConfigDataFilename, kLocalResource, "application/javascript"}, |
61 {kThemeCSSFilename, kLocalResource, "text/css"}, | 73 {kThemeCSSFilename, kLocalResource, "text/css"}, |
62 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"}, | 74 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"}, |
63 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"}, | 75 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"}, |
64 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"}, | 76 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"}, |
65 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"}, | 77 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"}, |
| 78 {kOneGoogleBarScriptFilename, kLocalResource, "text/javascript"}, |
| 79 {kOneGoogleBarInHeadStyleFilename, kLocalResource, "text/css"}, |
| 80 {kOneGoogleBarInHeadScriptFilename, kLocalResource, "text/javascript"}, |
| 81 {kOneGoogleBarAfterBarScriptFilename, kLocalResource, "text/javascript"}, |
| 82 {kOneGoogleBarEndOfBodyScriptFilename, kLocalResource, "text/javascript"}, |
66 }; | 83 }; |
67 | 84 |
68 // Strips any query parameters from the specified path. | 85 // Strips any query parameters from the specified path. |
69 std::string StripParameters(const std::string& path) { | 86 std::string StripParameters(const std::string& path) { |
70 return path.substr(0, path.find("?")); | 87 return path.substr(0, path.find("?")); |
71 } | 88 } |
72 | 89 |
73 // Adds a localized string keyed by resource id to the dictionary. | 90 // Adds a localized string keyed by resource id to the dictionary. |
74 void AddString(base::DictionaryValue* dictionary, | 91 void AddString(base::DictionaryValue* dictionary, |
75 const std::string& key, | 92 const std::string& key, |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 | 170 |
154 bool DefaultSearchProviderIsGoogleImpl( | 171 bool DefaultSearchProviderIsGoogleImpl( |
155 const TemplateURLService* template_url_service) { | 172 const TemplateURLService* template_url_service) { |
156 const TemplateURL* default_provider = | 173 const TemplateURL* default_provider = |
157 template_url_service->GetDefaultSearchProvider(); | 174 template_url_service->GetDefaultSearchProvider(); |
158 return default_provider && (default_provider->GetEngineType( | 175 return default_provider && (default_provider->GetEngineType( |
159 template_url_service->search_terms_data()) == | 176 template_url_service->search_terms_data()) == |
160 SEARCH_ENGINE_GOOGLE); | 177 SEARCH_ENGINE_GOOGLE); |
161 } | 178 } |
162 | 179 |
| 180 std::unique_ptr<base::DictionaryValue> ConvertOGBDataToDict( |
| 181 const OneGoogleBarData& og) { |
| 182 auto result = base::MakeUnique<base::DictionaryValue>(); |
| 183 // Only provide the html parts here. The js and css are injected separately |
| 184 // via <script src=...> and <link rel="stylesheet" href=...>. |
| 185 result->SetString("html", og.bar_html); |
| 186 result->SetString("end_of_body_html", og.end_of_body_html); |
| 187 return result; |
| 188 } |
| 189 |
163 } // namespace | 190 } // namespace |
164 | 191 |
165 class LocalNtpSource::GoogleSearchProviderTracker | 192 class LocalNtpSource::GoogleSearchProviderTracker |
166 : public TemplateURLServiceObserver { | 193 : public TemplateURLServiceObserver { |
167 public: | 194 public: |
168 using SearchProviderIsGoogleChangedCallback = | 195 using SearchProviderIsGoogleChangedCallback = |
169 base::Callback<void(bool is_google)>; | 196 base::Callback<void(bool is_google)>; |
170 | 197 |
171 GoogleSearchProviderTracker( | 198 GoogleSearchProviderTracker( |
172 TemplateURLService* service, | 199 TemplateURLService* service, |
(...skipping 25 matching lines...) Expand all Loading... |
198 } | 225 } |
199 | 226 |
200 TemplateURLService* service_; | 227 TemplateURLService* service_; |
201 SearchProviderIsGoogleChangedCallback callback_; | 228 SearchProviderIsGoogleChangedCallback callback_; |
202 | 229 |
203 bool is_google_; | 230 bool is_google_; |
204 }; | 231 }; |
205 | 232 |
206 LocalNtpSource::LocalNtpSource(Profile* profile) | 233 LocalNtpSource::LocalNtpSource(Profile* profile) |
207 : profile_(profile), | 234 : profile_(profile), |
| 235 one_google_bar_service_(nullptr), |
| 236 one_google_bar_service_observer_(this), |
208 default_search_provider_is_google_(false), | 237 default_search_provider_is_google_(false), |
209 default_search_provider_is_google_io_thread_(false), | 238 default_search_provider_is_google_io_thread_(false), |
210 weak_ptr_factory_(this) { | 239 weak_ptr_factory_(this) { |
211 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 240 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
212 | 241 |
| 242 if (base::FeatureList::IsEnabled(kOneGoogleBarOnLocalNtpFeature)) { |
| 243 one_google_bar_service_ = |
| 244 OneGoogleBarServiceFactory::GetForProfile(profile_); |
| 245 } |
| 246 |
| 247 // |one_google_bar_service_| is null in incognito, or when the feature is |
| 248 // disabled. |
| 249 if (one_google_bar_service_) |
| 250 one_google_bar_service_observer_.Add(one_google_bar_service_); |
| 251 |
213 TemplateURLService* template_url_service = | 252 TemplateURLService* template_url_service = |
214 TemplateURLServiceFactory::GetForProfile(profile_); | 253 TemplateURLServiceFactory::GetForProfile(profile_); |
215 if (template_url_service) { | 254 if (template_url_service) { |
216 google_tracker_ = base::MakeUnique<GoogleSearchProviderTracker>( | 255 google_tracker_ = base::MakeUnique<GoogleSearchProviderTracker>( |
217 template_url_service, | 256 template_url_service, |
218 base::Bind(&LocalNtpSource::DefaultSearchProviderIsGoogleChanged, | 257 base::Bind(&LocalNtpSource::DefaultSearchProviderIsGoogleChanged, |
219 base::Unretained(this))); | 258 base::Unretained(this))); |
220 DefaultSearchProviderIsGoogleChanged( | 259 DefaultSearchProviderIsGoogleChanged( |
221 google_tracker_->DefaultSearchProviderIsGoogle()); | 260 google_tracker_->DefaultSearchProviderIsGoogle()); |
222 } | 261 } |
(...skipping 17 matching lines...) Expand all Loading... |
240 GetConfigData(default_search_provider_is_google_); | 279 GetConfigData(default_search_provider_is_google_); |
241 callback.Run(base::RefCountedString::TakeString(&config_data_js)); | 280 callback.Run(base::RefCountedString::TakeString(&config_data_js)); |
242 return; | 281 return; |
243 } | 282 } |
244 if (stripped_path == kThemeCSSFilename) { | 283 if (stripped_path == kThemeCSSFilename) { |
245 std::string theme_css = GetThemeCSS(profile_); | 284 std::string theme_css = GetThemeCSS(profile_); |
246 callback.Run(base::RefCountedString::TakeString(&theme_css)); | 285 callback.Run(base::RefCountedString::TakeString(&theme_css)); |
247 return; | 286 return; |
248 } | 287 } |
249 | 288 |
| 289 if (base::StartsWith(stripped_path, "one-google", |
| 290 base::CompareCase::SENSITIVE)) { |
| 291 if (!one_google_bar_service_) { |
| 292 callback.Run(nullptr); |
| 293 return; |
| 294 } |
| 295 |
| 296 const base::Optional<OneGoogleBarData>& data = |
| 297 one_google_bar_service_->one_google_bar_data(); |
| 298 |
| 299 // The OneGoogleBar injector helper. |
| 300 if (stripped_path == kOneGoogleBarScriptFilename) { |
| 301 one_google_callbacks_.push_back(callback); |
| 302 |
| 303 // If there already is (cached) OGB data, serve it immediately. |
| 304 if (data.has_value()) |
| 305 ServeOneGoogleBar(*data); |
| 306 |
| 307 // In any case, request a refresh. |
| 308 one_google_bar_service_->Refresh(); |
| 309 } else { |
| 310 // The actual OneGoogleBar sources. |
| 311 std::string result; |
| 312 if (data.has_value()) { |
| 313 if (stripped_path == kOneGoogleBarInHeadStyleFilename) { |
| 314 result = data->in_head_style; |
| 315 } else if (stripped_path == kOneGoogleBarInHeadScriptFilename) { |
| 316 result = data->in_head_script; |
| 317 } else if (stripped_path == kOneGoogleBarAfterBarScriptFilename) { |
| 318 result = data->after_bar_script; |
| 319 } else if (stripped_path == kOneGoogleBarEndOfBodyScriptFilename) { |
| 320 result = data->end_of_body_script; |
| 321 } |
| 322 } |
| 323 callback.Run(base::RefCountedString::TakeString(&result)); |
| 324 } |
| 325 |
| 326 return; |
| 327 } |
| 328 |
250 #if !defined(GOOGLE_CHROME_BUILD) | 329 #if !defined(GOOGLE_CHROME_BUILD) |
251 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 330 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
252 if (command_line->HasSwitch(switches::kLocalNtpReload)) { | 331 if (command_line->HasSwitch(switches::kLocalNtpReload)) { |
253 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || | 332 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || |
254 stripped_path == "local-ntp.css") { | 333 stripped_path == "local-ntp.css") { |
255 base::ReplaceChars(stripped_path, "-", "_", &stripped_path); | 334 base::ReplaceChars(stripped_path, "-", "_", &stripped_path); |
256 local_ntp::SendLocalFileResource(stripped_path, callback); | 335 local_ntp::SendLocalFileResource(stripped_path, callback); |
257 return; | 336 return; |
258 } | 337 } |
259 } | 338 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 // While live-editing the local NTP files, turn off CSP. | 415 // While live-editing the local NTP files, turn off CSP. |
337 return "script-src *;"; | 416 return "script-src *;"; |
338 } | 417 } |
339 #endif // !defined(GOOGLE_CHROME_BUILD) | 418 #endif // !defined(GOOGLE_CHROME_BUILD) |
340 | 419 |
341 return "script-src 'strict-dynamic' " | 420 return "script-src 'strict-dynamic' " |
342 "'sha256-" + | 421 "'sha256-" + |
343 GetIntegritySha256Value( | 422 GetIntegritySha256Value( |
344 GetConfigData(default_search_provider_is_google_io_thread_)) + | 423 GetConfigData(default_search_provider_is_google_io_thread_)) + |
345 "' " | 424 "' " |
346 "'sha256-g38WaUaxnOIWY7E2LtLZ5ff9r5sn1dBj80jevt/kmx0=';"; | 425 "'sha256-ROPmcormZEipZzy3Ff+o345FFrhHWsAZjBpGIyZzCYY=';"; |
347 } | 426 } |
348 | 427 |
349 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { | 428 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { |
350 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 429 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
351 | 430 |
352 // Allow embedding of most visited iframes. | 431 if (one_google_bar_service_) { |
| 432 // Allow embedding of the most visited iframe, as well as the account |
| 433 // switcher and the notifications dropdown from the One Google Bar. |
| 434 // TODO(treib): Figure out a way to also allow staging instances. |
| 435 return base::StringPrintf( |
| 436 "child-src %s https://accounts.google.com/ https://docs.google.com " |
| 437 "https://notifications.google.com;", |
| 438 chrome::kChromeSearchMostVisitedUrl); |
| 439 } |
| 440 // Allow embedding of the most visited iframe. |
353 return base::StringPrintf("child-src %s;", | 441 return base::StringPrintf("child-src %s;", |
354 chrome::kChromeSearchMostVisitedUrl); | 442 chrome::kChromeSearchMostVisitedUrl); |
355 } | 443 } |
356 | 444 |
| 445 void LocalNtpSource::OnOneGoogleBarDataChanged() { |
| 446 const base::Optional<OneGoogleBarData>& data = |
| 447 one_google_bar_service_->one_google_bar_data(); |
| 448 if (data.has_value()) |
| 449 ServeOneGoogleBar(*data); |
| 450 else |
| 451 ServeNullOneGoogleBar(); |
| 452 } |
| 453 |
| 454 void LocalNtpSource::OnOneGoogleBarFetchFailed() { |
| 455 ServeNullOneGoogleBar(); |
| 456 } |
| 457 |
| 458 void LocalNtpSource::OnOneGoogleBarServiceShuttingDown() { |
| 459 one_google_bar_service_observer_.RemoveAll(); |
| 460 one_google_bar_service_ = nullptr; |
| 461 } |
| 462 |
| 463 void LocalNtpSource::ServeOneGoogleBar(const OneGoogleBarData& data) { |
| 464 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 465 |
| 466 if (one_google_callbacks_.empty()) |
| 467 return; |
| 468 |
| 469 std::string json; |
| 470 base::JSONWriter::Write(*ConvertOGBDataToDict(data), &json); |
| 471 for (auto& callback : one_google_callbacks_) { |
| 472 std::string data = "var og = " + json + ";"; |
| 473 callback.Run(base::RefCountedString::TakeString(&data)); |
| 474 } |
| 475 one_google_callbacks_.clear(); |
| 476 } |
| 477 |
| 478 void LocalNtpSource::ServeNullOneGoogleBar() { |
| 479 for (auto& callback : one_google_callbacks_) |
| 480 callback.Run(nullptr); |
| 481 one_google_callbacks_.clear(); |
| 482 } |
| 483 |
357 void LocalNtpSource::DefaultSearchProviderIsGoogleChanged(bool is_google) { | 484 void LocalNtpSource::DefaultSearchProviderIsGoogleChanged(bool is_google) { |
358 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 485 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
359 | 486 |
360 default_search_provider_is_google_ = is_google; | 487 default_search_provider_is_google_ = is_google; |
361 content::BrowserThread::PostTask( | 488 content::BrowserThread::PostTask( |
362 content::BrowserThread::IO, FROM_HERE, | 489 content::BrowserThread::IO, FROM_HERE, |
363 base::Bind(&LocalNtpSource::SetDefaultSearchProviderIsGoogleOnIOThread, | 490 base::Bind(&LocalNtpSource::SetDefaultSearchProviderIsGoogleOnIOThread, |
364 weak_ptr_factory_.GetWeakPtr(), is_google)); | 491 weak_ptr_factory_.GetWeakPtr(), is_google)); |
365 } | 492 } |
366 | 493 |
367 void LocalNtpSource::SetDefaultSearchProviderIsGoogleOnIOThread( | 494 void LocalNtpSource::SetDefaultSearchProviderIsGoogleOnIOThread( |
368 bool is_google) { | 495 bool is_google) { |
369 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 496 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
370 | 497 |
371 default_search_provider_is_google_io_thread_ = is_google; | 498 default_search_provider_is_google_io_thread_ = is_google; |
372 } | 499 } |
OLD | NEW |