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> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
11 #include "base/base64.h" | |
11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
12 #include "base/json/json_string_value_serializer.h" | 13 #include "base/json/json_string_value_serializer.h" |
13 #include "base/logging.h" | 14 #include "base/logging.h" |
14 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
15 #include "base/memory/ref_counted_memory.h" | 16 #include "base/memory/ref_counted_memory.h" |
16 #include "base/metrics/field_trial.h" | |
17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "base/values.h" | 19 #include "base/values.h" |
20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
21 #include "chrome/browser/search/google_search_provider_service.h" | |
22 #include "chrome/browser/search/google_search_provider_service_factory.h" | |
21 #include "chrome/browser/search/instant_io_context.h" | 23 #include "chrome/browser/search/instant_io_context.h" |
22 #include "chrome/browser/search/local_files_ntp_source.h" | 24 #include "chrome/browser/search/local_files_ntp_source.h" |
23 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
24 #include "chrome/browser/themes/theme_properties.h" | 25 #include "chrome/browser/themes/theme_properties.h" |
25 #include "chrome/browser/themes/theme_service.h" | 26 #include "chrome/browser/themes/theme_service.h" |
26 #include "chrome/browser/themes/theme_service_factory.h" | 27 #include "chrome/browser/themes/theme_service_factory.h" |
27 #include "chrome/common/chrome_switches.h" | 28 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/url_constants.h" | 29 #include "chrome/common/url_constants.h" |
29 #include "chrome/grit/browser_resources.h" | 30 #include "chrome/grit/browser_resources.h" |
30 #include "chrome/grit/generated_resources.h" | 31 #include "chrome/grit/generated_resources.h" |
31 #include "chrome/grit/theme_resources.h" | 32 #include "chrome/grit/theme_resources.h" |
32 #include "components/search_engines/template_url_service.h" | |
33 #include "components/strings/grit/components_strings.h" | 33 #include "components/strings/grit/components_strings.h" |
34 #include "crypto/secure_hash.h" | |
35 #include "net/base/hash_value.h" | |
34 #include "net/url_request/url_request.h" | 36 #include "net/url_request/url_request.h" |
35 #include "third_party/skia/include/core/SkColor.h" | 37 #include "third_party/skia/include/core/SkColor.h" |
36 #include "ui/base/l10n/l10n_util.h" | 38 #include "ui/base/l10n/l10n_util.h" |
37 #include "ui/base/resource/resource_bundle.h" | 39 #include "ui/base/resource/resource_bundle.h" |
38 #include "ui/base/webui/web_ui_util.h" | 40 #include "ui/base/webui/web_ui_util.h" |
39 #include "ui/resources/grit/ui_resources.h" | 41 #include "ui/resources/grit/ui_resources.h" |
40 #include "url/gurl.h" | 42 #include "url/gurl.h" |
41 | 43 |
42 namespace { | 44 namespace { |
43 | 45 |
44 // Signifies a locally constructed resource, i.e. not from grit/. | 46 // Signifies a locally constructed resource, i.e. not from grit/. |
45 const int kLocalResource = -1; | 47 const int kLocalResource = -1; |
46 | 48 |
47 const char kConfigDataFilename[] = "config.js"; | 49 const char kConfigDataFilename[] = "config.js"; |
48 const char kThemeCSSFilename[] = "theme.css"; | 50 const char kThemeCSSFilename[] = "theme.css"; |
51 const char kMainHtmlFilename[] = "local-ntp.html"; | |
49 | 52 |
50 const struct Resource{ | 53 const struct Resource{ |
51 const char* filename; | 54 const char* filename; |
52 int identifier; | 55 int identifier; |
53 const char* mime_type; | 56 const char* mime_type; |
54 } kResources[] = { | 57 } kResources[] = { |
55 {"local-ntp.html", IDR_LOCAL_NTP_HTML, "text/html"}, | 58 {kMainHtmlFilename, kLocalResource, "text/html"}, |
56 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"}, | 59 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"}, |
57 {kConfigDataFilename, kLocalResource, "application/javascript"}, | 60 {kConfigDataFilename, kLocalResource, "application/javascript"}, |
58 {kThemeCSSFilename, kLocalResource, "text/css"}, | 61 {kThemeCSSFilename, kLocalResource, "text/css"}, |
59 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"}, | 62 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"}, |
60 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"}, | 63 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"}, |
61 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"}, | 64 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"}, |
62 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"}, | 65 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"}, |
63 }; | 66 }; |
64 | 67 |
65 // Strips any query parameters from the specified path. | 68 // Strips any query parameters from the specified path. |
66 std::string StripParameters(const std::string& path) { | 69 std::string StripParameters(const std::string& path) { |
67 return path.substr(0, path.find("?")); | 70 return path.substr(0, path.find("?")); |
68 } | 71 } |
69 | 72 |
70 bool DefaultSearchProviderIsGoogle(Profile* profile) { | |
71 if (!profile) | |
72 return false; | |
73 | |
74 TemplateURLService* template_url_service = | |
75 TemplateURLServiceFactory::GetForProfile(profile); | |
76 if (!template_url_service) | |
77 return false; | |
78 | |
79 const TemplateURL* default_provider = | |
80 template_url_service->GetDefaultSearchProvider(); | |
81 return default_provider && | |
82 (default_provider->GetEngineType( | |
83 template_url_service->search_terms_data()) == | |
84 SEARCH_ENGINE_GOOGLE); | |
85 } | |
86 | |
87 // Adds a localized string keyed by resource id to the dictionary. | 73 // Adds a localized string keyed by resource id to the dictionary. |
88 void AddString(base::DictionaryValue* dictionary, | 74 void AddString(base::DictionaryValue* dictionary, |
89 const std::string& key, | 75 const std::string& key, |
90 int resource_id) { | 76 int resource_id) { |
91 dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id)); | 77 dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id)); |
92 } | 78 } |
93 | 79 |
94 // Populates |translated_strings| dictionary for the local NTP. |is_google| | 80 // Populates |translated_strings| dictionary for the local NTP. |is_google| |
95 // indicates that this page is the Google local NTP. | 81 // indicates that this page is the Google local NTP. |
96 std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) { | 82 std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) { |
(...skipping 12 matching lines...) Expand all Loading... | |
109 AddString(translated_strings.get(), "title", IDS_NEW_TAB_TITLE); | 95 AddString(translated_strings.get(), "title", IDS_NEW_TAB_TITLE); |
110 if (is_google) { | 96 if (is_google) { |
111 AddString(translated_strings.get(), "searchboxPlaceholder", | 97 AddString(translated_strings.get(), "searchboxPlaceholder", |
112 IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT); | 98 IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT); |
113 } | 99 } |
114 | 100 |
115 return translated_strings; | 101 return translated_strings; |
116 } | 102 } |
117 | 103 |
118 // Returns a JS dictionary of configuration data for the local NTP. | 104 // Returns a JS dictionary of configuration data for the local NTP. |
119 std::string GetConfigData(Profile* profile) { | 105 std::string GetConfigData(bool is_google) { |
120 base::DictionaryValue config_data; | 106 base::DictionaryValue config_data; |
121 bool is_google = DefaultSearchProviderIsGoogle(profile); | |
122 config_data.Set("translatedStrings", GetTranslatedStrings(is_google)); | 107 config_data.Set("translatedStrings", GetTranslatedStrings(is_google)); |
123 config_data.SetBoolean("isGooglePage", is_google); | 108 config_data.SetBoolean("isGooglePage", is_google); |
124 | 109 |
125 // Serialize the dictionary. | 110 // Serialize the dictionary. |
126 std::string js_text; | 111 std::string js_text; |
127 JSONStringValueSerializer serializer(&js_text); | 112 JSONStringValueSerializer serializer(&js_text); |
128 serializer.Serialize(config_data); | 113 serializer.Serialize(config_data); |
129 | 114 |
130 std::string config_data_js; | 115 std::string config_data_js; |
131 config_data_js.append("var configData = "); | 116 config_data_js.append("var configData = "); |
132 config_data_js.append(js_text); | 117 config_data_js.append(js_text); |
133 config_data_js.append(";"); | 118 config_data_js.append(";"); |
134 return config_data_js; | 119 return config_data_js; |
135 } | 120 } |
136 | 121 |
122 std::string GetIntegritySha256Value(const std::string& data) { | |
123 // Compute the sha256 hash. | |
124 net::SHA256HashValue hash_value; | |
125 std::unique_ptr<crypto::SecureHash> hash( | |
126 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
127 hash->Update(data.data(), data.size()); | |
128 hash->Finish(&hash_value, sizeof(hash_value)); | |
129 | |
130 // Base64-encode it. | |
131 base::StringPiece hash_value_str( | |
132 reinterpret_cast<const char*>(hash_value.data), sizeof(hash_value)); | |
133 std::string result; | |
134 base::Base64Encode(hash_value_str, &result); | |
135 return result; | |
136 } | |
137 | |
137 std::string GetThemeCSS(Profile* profile) { | 138 std::string GetThemeCSS(Profile* profile) { |
138 SkColor background_color = | 139 SkColor background_color = |
139 ThemeService::GetThemeProviderForProfile(profile) | 140 ThemeService::GetThemeProviderForProfile(profile) |
140 .GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); | 141 .GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); |
141 | 142 |
142 return base::StringPrintf("body { background-color: #%02X%02X%02X; }", | 143 return base::StringPrintf("body { background-color: #%02X%02X%02X; }", |
143 SkColorGetR(background_color), | 144 SkColorGetR(background_color), |
144 SkColorGetG(background_color), | 145 SkColorGetG(background_color), |
145 SkColorGetB(background_color)); | 146 SkColorGetB(background_color)); |
146 } | 147 } |
147 | 148 |
148 std::string GetLocalNtpPath() { | 149 std::string GetLocalNtpPath() { |
149 return std::string(chrome::kChromeSearchScheme) + "://" + | 150 return std::string(chrome::kChromeSearchScheme) + "://" + |
150 std::string(chrome::kChromeSearchLocalNtpHost) + "/"; | 151 std::string(chrome::kChromeSearchLocalNtpHost) + "/"; |
151 } | 152 } |
152 | 153 |
153 } // namespace | 154 } // namespace |
154 | 155 |
155 LocalNtpSource::LocalNtpSource(Profile* profile) : profile_(profile) {} | 156 LocalNtpSource::LocalNtpSource(Profile* profile) |
157 : profile_(profile), | |
158 default_search_provider_observer_(this), | |
159 default_search_provider_is_google_(false) { | |
160 GoogleSearchProviderService* google_service = | |
161 GoogleSearchProviderServiceFactory::GetForProfile(profile_); | |
162 if (google_service) { | |
163 default_search_provider_observer_.Add(google_service); | |
164 default_search_provider_is_google_ = | |
165 google_service->DefaultSearchProviderIsGoogle(); | |
166 } | |
167 } | |
156 | 168 |
157 LocalNtpSource::~LocalNtpSource() = default; | 169 LocalNtpSource::~LocalNtpSource() = default; |
158 | 170 |
159 std::string LocalNtpSource::GetSource() const { | 171 std::string LocalNtpSource::GetSource() const { |
160 return chrome::kChromeSearchLocalNtpHost; | 172 return chrome::kChromeSearchLocalNtpHost; |
161 } | 173 } |
162 | 174 |
163 void LocalNtpSource::StartDataRequest( | 175 void LocalNtpSource::StartDataRequest( |
164 const std::string& path, | 176 const std::string& path, |
165 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, | 177 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, |
166 const content::URLDataSource::GotDataCallback& callback) { | 178 const content::URLDataSource::GotDataCallback& callback) { |
167 std::string stripped_path = StripParameters(path); | 179 std::string stripped_path = StripParameters(path); |
168 if (stripped_path == kConfigDataFilename) { | 180 if (stripped_path == kConfigDataFilename) { |
169 std::string config_data_js = GetConfigData(profile_); | 181 std::string config_data_js = |
182 GetConfigData(default_search_provider_is_google_); | |
170 callback.Run(base::RefCountedString::TakeString(&config_data_js)); | 183 callback.Run(base::RefCountedString::TakeString(&config_data_js)); |
171 return; | 184 return; |
172 } | 185 } |
173 if (stripped_path == kThemeCSSFilename) { | 186 if (stripped_path == kThemeCSSFilename) { |
174 std::string theme_css = GetThemeCSS(profile_); | 187 std::string theme_css = GetThemeCSS(profile_); |
175 callback.Run(base::RefCountedString::TakeString(&theme_css)); | 188 callback.Run(base::RefCountedString::TakeString(&theme_css)); |
176 return; | 189 return; |
177 } | 190 } |
178 | 191 |
179 #if !defined(GOOGLE_CHROME_BUILD) | 192 #if !defined(GOOGLE_CHROME_BUILD) |
180 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 193 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
181 if (command_line->HasSwitch(switches::kLocalNtpReload)) { | 194 if (command_line->HasSwitch(switches::kLocalNtpReload)) { |
182 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || | 195 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || |
183 stripped_path == "local-ntp.css") { | 196 stripped_path == "local-ntp.css") { |
184 base::ReplaceChars(stripped_path, "-", "_", &stripped_path); | 197 base::ReplaceChars(stripped_path, "-", "_", &stripped_path); |
185 local_ntp::SendLocalFileResource(stripped_path, callback); | 198 local_ntp::SendLocalFileResource(stripped_path, callback); |
186 return; | 199 return; |
187 } | 200 } |
188 } | 201 } |
189 #endif // !defined(GOOGLE_CHROME_BUILD) | 202 #endif // !defined(GOOGLE_CHROME_BUILD) |
190 | 203 |
204 if (stripped_path == kMainHtmlFilename) { | |
205 std::string html = ResourceBundle::GetSharedInstance() | |
206 .GetRawDataResource(IDR_LOCAL_NTP_HTML) | |
207 .as_string(); | |
208 std::string config_sha256 = | |
209 "sha256-" + GetIntegritySha256Value( | |
210 GetConfigData(default_search_provider_is_google_)); | |
211 base::ReplaceFirstSubstringAfterOffset(&html, 0, "{{CONFIG_INTEGRITY}}", | |
212 config_sha256); | |
213 callback.Run(base::RefCountedString::TakeString(&html)); | |
214 return; | |
215 } | |
216 | |
191 float scale = 1.0f; | 217 float scale = 1.0f; |
192 std::string filename; | 218 std::string filename; |
193 webui::ParsePathAndScale( | 219 webui::ParsePathAndScale( |
194 GURL(GetLocalNtpPath() + stripped_path), &filename, &scale); | 220 GURL(GetLocalNtpPath() + stripped_path), &filename, &scale); |
195 ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(scale); | 221 ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(scale); |
196 | 222 |
197 for (size_t i = 0; i < arraysize(kResources); ++i) { | 223 for (size_t i = 0; i < arraysize(kResources); ++i) { |
198 if (filename == kResources[i].filename) { | 224 if (filename == kResources[i].filename) { |
199 scoped_refptr<base::RefCountedMemory> response( | 225 scoped_refptr<base::RefCountedMemory> response( |
200 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( | 226 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( |
201 kResources[i].identifier, scale_factor)); | 227 kResources[i].identifier, scale_factor)); |
202 callback.Run(response.get()); | 228 callback.Run(response.get()); |
203 return; | 229 return; |
204 } | 230 } |
205 } | 231 } |
206 callback.Run(NULL); | 232 callback.Run(nullptr); |
207 } | 233 } |
208 | 234 |
209 std::string LocalNtpSource::GetMimeType( | 235 std::string LocalNtpSource::GetMimeType( |
210 const std::string& path) const { | 236 const std::string& path) const { |
211 const std::string stripped_path = StripParameters(path); | 237 const std::string stripped_path = StripParameters(path); |
212 for (size_t i = 0; i < arraysize(kResources); ++i) { | 238 for (size_t i = 0; i < arraysize(kResources); ++i) { |
213 if (stripped_path == kResources[i].filename) | 239 if (stripped_path == kResources[i].filename) |
214 return kResources[i].mime_type; | 240 return kResources[i].mime_type; |
215 } | 241 } |
216 return std::string(); | 242 return std::string(); |
217 } | 243 } |
218 | 244 |
219 bool LocalNtpSource::AllowCaching() const { | 245 bool LocalNtpSource::AllowCaching() const { |
220 // Some resources served by LocalNtpSource, i.e. config.js, are dynamically | 246 // Some resources served by LocalNtpSource, i.e. config.js, are dynamically |
221 // generated and could differ on each access. To avoid using old cached | 247 // generated and could differ on each access. To avoid using old cached |
222 // content on reload, disallow caching here. Otherwise, it fails to reflect | 248 // content on reload, disallow caching here. Otherwise, it fails to reflect |
223 // newly revised user configurations in the page. | 249 // newly revised user configurations in the page. |
224 return false; | 250 return false; |
225 } | 251 } |
226 | 252 |
227 bool LocalNtpSource::ShouldServiceRequest( | 253 bool LocalNtpSource::ShouldServiceRequest( |
228 const net::URLRequest* request) const { | 254 const net::URLRequest* request) const { |
229 DCHECK(request->url().host_piece() == chrome::kChromeSearchLocalNtpHost); | 255 DCHECK(request->url().host_piece() == chrome::kChromeSearchLocalNtpHost); |
230 if (!InstantIOContext::ShouldServiceRequest(request)) | 256 if (!InstantIOContext::ShouldServiceRequest(request)) |
231 return false; | 257 return false; |
232 | 258 |
233 if (request->url().SchemeIs(chrome::kChromeSearchScheme)) { | 259 if (request->url().SchemeIs(chrome::kChromeSearchScheme)) { |
234 std::string filename; | 260 std::string filename; |
235 webui::ParsePathAndScale(request->url(), &filename, NULL); | 261 webui::ParsePathAndScale(request->url(), &filename, nullptr); |
236 for (size_t i = 0; i < arraysize(kResources); ++i) { | 262 for (size_t i = 0; i < arraysize(kResources); ++i) { |
237 if (filename == kResources[i].filename) | 263 if (filename == kResources[i].filename) |
238 return true; | 264 return true; |
239 } | 265 } |
240 } | 266 } |
241 return false; | 267 return false; |
242 } | 268 } |
243 | 269 |
270 std::string LocalNtpSource::GetContentSecurityPolicyScriptSrc() const { | |
271 // Note: This method is called on the IO thread. | |
272 #if !defined(GOOGLE_CHROME_BUILD) | |
273 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
274 if (command_line->HasSwitch(switches::kLocalNtpReload)) { | |
275 // While live-editing the local NTP files, turn off CSP. | |
276 return "script-src *;"; | |
277 } | |
278 #endif // !defined(GOOGLE_CHROME_BUILD) | |
279 | |
280 return "script-src 'strict-dynamic' " | |
281 "'sha256-" + | |
282 GetIntegritySha256Value( | |
283 GetConfigData(default_search_provider_is_google_)) + | |
284 "' " | |
285 "'sha256-g38WaUaxnOIWY7E2LtLZ5ff9r5sn1dBj80jevt/kmx0=';"; | |
286 } | |
287 | |
244 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { | 288 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { |
245 // Allow embedding of most visited iframes. | 289 // Allow embedding of most visited iframes. |
246 return base::StringPrintf("child-src %s;", | 290 return base::StringPrintf("child-src %s;", |
247 chrome::kChromeSearchMostVisitedUrl); | 291 chrome::kChromeSearchMostVisitedUrl); |
248 } | 292 } |
293 | |
294 void LocalNtpSource::OnDefaultSearchProviderIsGoogleChanged(bool is_google) { | |
295 default_search_provider_is_google_ = is_google; | |
sfiera
2017/04/11 09:45:17
What thread is this method called from? If it's th
Marc Treib
2017/04/11 12:37:59
Threading in URLDataSource is kind of a mess :( T
sfiera
2017/04/11 14:07:35
Alright, thanks. This is ugly, but feels like the
| |
296 } | |
297 | |
298 void LocalNtpSource::OnGoogleSearchProviderServiceShuttingDown() { | |
299 default_search_provider_observer_.RemoveAll(); | |
300 } | |
OLD | NEW |