OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/extensions/updater/extension_downloader.h" | 5 #include "chrome/browser/extensions/updater/extension_downloader.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "base/version.h" | 21 #include "base/version.h" |
22 #include "chrome/browser/chrome_notification_types.h" | 22 #include "chrome/browser/chrome_notification_types.h" |
23 #include "chrome/browser/extensions/updater/extension_cache.h" | 23 #include "chrome/browser/extensions/updater/extension_cache.h" |
24 #include "chrome/browser/extensions/updater/request_queue_impl.h" | 24 #include "chrome/browser/extensions/updater/request_queue_impl.h" |
25 #include "chrome/browser/extensions/updater/safe_manifest_parser.h" | 25 #include "chrome/browser/extensions/updater/safe_manifest_parser.h" |
26 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" | 26 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" |
27 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/chrome_version_info.h" | 28 #include "chrome/common/chrome_version_info.h" |
29 #include "chrome/common/extensions/extension_constants.h" | 29 #include "chrome/common/extensions/extension_constants.h" |
30 #include "chrome/common/extensions/manifest_url_handler.h" | 30 #include "chrome/common/extensions/manifest_url_handler.h" |
| 31 #include "components/omaha_query_params/omaha_query_params.h" |
31 #include "content/public/browser/browser_thread.h" | 32 #include "content/public/browser/browser_thread.h" |
32 #include "content/public/browser/notification_details.h" | 33 #include "content/public/browser/notification_details.h" |
33 #include "content/public/browser/notification_service.h" | 34 #include "content/public/browser/notification_service.h" |
34 #include "google_apis/gaia/identity_provider.h" | 35 #include "google_apis/gaia/identity_provider.h" |
35 #include "net/base/backoff_entry.h" | 36 #include "net/base/backoff_entry.h" |
36 #include "net/base/load_flags.h" | 37 #include "net/base/load_flags.h" |
37 #include "net/base/net_errors.h" | 38 #include "net/base/net_errors.h" |
38 #include "net/http/http_request_headers.h" | 39 #include "net/http/http_request_headers.h" |
39 #include "net/http/http_status_code.h" | 40 #include "net/http/http_status_code.h" |
40 #include "net/url_request/url_fetcher.h" | 41 #include "net/url_request/url_fetcher.h" |
41 #include "net/url_request/url_request_context_getter.h" | 42 #include "net/url_request/url_request_context_getter.h" |
42 #include "net/url_request/url_request_status.h" | 43 #include "net/url_request/url_request_status.h" |
43 | 44 |
44 using base::Time; | 45 using base::Time; |
45 using base::TimeDelta; | 46 using base::TimeDelta; |
46 using content::BrowserThread; | 47 using content::BrowserThread; |
| 48 using omaha_query_params::OmahaQueryParams; |
47 | 49 |
48 namespace extensions { | 50 namespace extensions { |
49 | 51 |
50 const char ExtensionDownloader::kBlacklistAppID[] = "com.google.crx.blacklist"; | 52 const char ExtensionDownloader::kBlacklistAppID[] = "com.google.crx.blacklist"; |
51 | 53 |
52 namespace { | 54 namespace { |
53 | 55 |
54 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { | 56 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { |
55 // Number of initial errors (in sequence) to ignore before applying | 57 // Number of initial errors (in sequence) to ignore before applying |
56 // exponential back-off rules. | 58 // exponential back-off rules. |
(...skipping 20 matching lines...) Expand all Loading... |
77 false, | 79 false, |
78 }; | 80 }; |
79 | 81 |
80 const char kAuthUserQueryKey[] = "authuser"; | 82 const char kAuthUserQueryKey[] = "authuser"; |
81 | 83 |
82 const int kMaxAuthUserValue = 10; | 84 const int kMaxAuthUserValue = 10; |
83 const int kMaxOAuth2Attempts = 3; | 85 const int kMaxOAuth2Attempts = 3; |
84 | 86 |
85 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; | 87 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; |
86 const char kDefaultInstallSource[] = ""; | 88 const char kDefaultInstallSource[] = ""; |
| 89 const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx"; |
87 | 90 |
88 const char kGoogleDotCom[] = "google.com"; | 91 const char kGoogleDotCom[] = "google.com"; |
89 const char kTokenServiceConsumerId[] = "extension_downloader"; | 92 const char kTokenServiceConsumerId[] = "extension_downloader"; |
90 const char kWebstoreOAuth2Scope[] = | 93 const char kWebstoreOAuth2Scope[] = |
91 "https://www.googleapis.com/auth/chromewebstore.readonly"; | 94 "https://www.googleapis.com/auth/chromewebstore.readonly"; |
92 | 95 |
93 #define RETRY_HISTOGRAM(name, retry_count, url) \ | 96 #define RETRY_HISTOGRAM(name, retry_count, url) \ |
94 if ((url).DomainIs(kGoogleDotCom)) { \ | 97 if ((url).DomainIs(kGoogleDotCom)) { \ |
95 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountGoogleUrl", \ | 98 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountGoogleUrl", \ |
96 retry_count, \ | 99 retry_count, \ |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 return false; | 206 return false; |
204 } | 207 } |
205 | 208 |
206 // If the extension updates itself from the gallery, ignore any update URL | 209 // If the extension updates itself from the gallery, ignore any update URL |
207 // data. At the moment there is no extra data that an extension can | 210 // data. At the moment there is no extra data that an extension can |
208 // communicate to the the gallery update servers. | 211 // communicate to the the gallery update servers. |
209 std::string update_url_data; | 212 std::string update_url_data; |
210 if (!ManifestURL::UpdatesFromGallery(&extension)) | 213 if (!ManifestURL::UpdatesFromGallery(&extension)) |
211 update_url_data = delegate_->GetUpdateUrlData(extension.id()); | 214 update_url_data = delegate_->GetUpdateUrlData(extension.id()); |
212 | 215 |
213 return AddExtensionData(extension.id(), *extension.version(), | 216 // If the browser's native architecture has changed since this extension was |
| 217 // installed, we need to force an update. |
| 218 bool force_update = false; |
| 219 std::string install_source; |
| 220 std::set<std::string> archs; |
| 221 extension.GetPlatformSpecificResourceArchs(&archs); |
| 222 if (!archs.empty() && |
| 223 archs.find(OmahaQueryParams::GetNaclArch()) == archs.end()) { |
| 224 force_update = true; |
| 225 install_source = kWrongMultiCrxInstallSource; |
| 226 } |
| 227 |
| 228 return AddExtensionData(extension.id(), |
| 229 *extension.version(), |
214 extension.GetType(), | 230 extension.GetType(), |
215 ManifestURL::GetUpdateURL(&extension), | 231 ManifestURL::GetUpdateURL(&extension), |
216 update_url_data, request_id); | 232 update_url_data, |
| 233 request_id, |
| 234 force_update, |
| 235 install_source); |
217 } | 236 } |
218 | 237 |
219 bool ExtensionDownloader::AddPendingExtension(const std::string& id, | 238 bool ExtensionDownloader::AddPendingExtension(const std::string& id, |
220 const GURL& update_url, | 239 const GURL& update_url, |
221 int request_id) { | 240 int request_id) { |
222 // Use a zero version to ensure that a pending extension will always | 241 // Use a zero version to ensure that a pending extension will always |
223 // be updated, and thus installed (assuming all extensions have | 242 // be updated, and thus installed (assuming all extensions have |
224 // non-zero versions). | 243 // non-zero versions). |
225 Version version("0.0.0.0"); | 244 Version version("0.0.0.0"); |
226 DCHECK(version.IsValid()); | 245 DCHECK(version.IsValid()); |
227 | 246 |
228 return AddExtensionData(id, | 247 return AddExtensionData(id, |
229 version, | 248 version, |
230 Manifest::TYPE_UNKNOWN, | 249 Manifest::TYPE_UNKNOWN, |
231 update_url, | 250 update_url, |
232 std::string(), | 251 std::string(), |
233 request_id); | 252 request_id, |
| 253 false, |
| 254 std::string()); |
234 } | 255 } |
235 | 256 |
236 void ExtensionDownloader::StartAllPending(ExtensionCache* cache) { | 257 void ExtensionDownloader::StartAllPending(ExtensionCache* cache) { |
237 if (cache) { | 258 if (cache) { |
238 extension_cache_ = cache; | 259 extension_cache_ = cache; |
239 extension_cache_->Start(base::Bind( | 260 extension_cache_->Start(base::Bind( |
240 &ExtensionDownloader::DoStartAllPending, | 261 &ExtensionDownloader::DoStartAllPending, |
241 weak_ptr_factory_.GetWeakPtr())); | 262 weak_ptr_factory_.GetWeakPtr())); |
242 } else { | 263 } else { |
243 DoStartAllPending(); | 264 DoStartAllPending(); |
(...skipping 22 matching lines...) Expand all Loading... |
266 // url here to avoid DNS hijacking of the blacklist, which is not validated | 287 // url here to avoid DNS hijacking of the blacklist, which is not validated |
267 // by a public key signature like .crx files are. | 288 // by a public key signature like .crx files are. |
268 scoped_ptr<ManifestFetchData> blacklist_fetch( | 289 scoped_ptr<ManifestFetchData> blacklist_fetch( |
269 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl(), | 290 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl(), |
270 request_id)); | 291 request_id)); |
271 DCHECK(blacklist_fetch->base_url().SchemeIsSecure()); | 292 DCHECK(blacklist_fetch->base_url().SchemeIsSecure()); |
272 blacklist_fetch->AddExtension(kBlacklistAppID, | 293 blacklist_fetch->AddExtension(kBlacklistAppID, |
273 version, | 294 version, |
274 &ping_data, | 295 &ping_data, |
275 std::string(), | 296 std::string(), |
276 kDefaultInstallSource); | 297 kDefaultInstallSource, |
| 298 false); |
277 StartUpdateCheck(blacklist_fetch.Pass()); | 299 StartUpdateCheck(blacklist_fetch.Pass()); |
278 } | 300 } |
279 | 301 |
280 void ExtensionDownloader::SetWebstoreIdentityProvider( | 302 void ExtensionDownloader::SetWebstoreIdentityProvider( |
281 scoped_ptr<IdentityProvider> identity_provider) { | 303 scoped_ptr<IdentityProvider> identity_provider) { |
282 identity_provider_.swap(identity_provider); | 304 identity_provider_.swap(identity_provider); |
283 } | 305 } |
284 | 306 |
285 bool ExtensionDownloader::AddExtensionData(const std::string& id, | 307 bool ExtensionDownloader::AddExtensionData( |
286 const Version& version, | 308 const std::string& id, |
287 Manifest::Type extension_type, | 309 const Version& version, |
288 const GURL& extension_update_url, | 310 Manifest::Type extension_type, |
289 const std::string& update_url_data, | 311 const GURL& extension_update_url, |
290 int request_id) { | 312 const std::string& update_url_data, |
| 313 int request_id, |
| 314 bool force_update, |
| 315 const std::string& install_source_override) { |
291 GURL update_url(extension_update_url); | 316 GURL update_url(extension_update_url); |
292 // Skip extensions with non-empty invalid update URLs. | 317 // Skip extensions with non-empty invalid update URLs. |
293 if (!update_url.is_empty() && !update_url.is_valid()) { | 318 if (!update_url.is_empty() && !update_url.is_valid()) { |
294 LOG(WARNING) << "Extension " << id << " has invalid update url " | 319 LOG(WARNING) << "Extension " << id << " has invalid update url " |
295 << update_url; | 320 << update_url; |
296 return false; | 321 return false; |
297 } | 322 } |
298 | 323 |
299 // Make sure we use SSL for store-hosted extensions. | 324 // Make sure we use SSL for store-hosted extensions. |
300 if (extension_urls::IsWebstoreUpdateUrl(update_url) && | 325 if (extension_urls::IsWebstoreUpdateUrl(update_url) && |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled()) { | 371 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled()) { |
347 update_urls.push_back(extension_urls::GetWebstoreUpdateUrl()); | 372 update_urls.push_back(extension_urls::GetWebstoreUpdateUrl()); |
348 } | 373 } |
349 | 374 |
350 for (size_t i = 0; i < update_urls.size(); ++i) { | 375 for (size_t i = 0; i < update_urls.size(); ++i) { |
351 DCHECK(!update_urls[i].is_empty()); | 376 DCHECK(!update_urls[i].is_empty()); |
352 DCHECK(update_urls[i].is_valid()); | 377 DCHECK(update_urls[i].is_valid()); |
353 | 378 |
354 std::string install_source = i == 0 ? | 379 std::string install_source = i == 0 ? |
355 kDefaultInstallSource : kNotFromWebstoreInstallSource; | 380 kDefaultInstallSource : kNotFromWebstoreInstallSource; |
| 381 if (!install_source_override.empty()) { |
| 382 install_source = install_source_override; |
| 383 } |
356 | 384 |
357 ManifestFetchData::PingData ping_data; | 385 ManifestFetchData::PingData ping_data; |
358 ManifestFetchData::PingData* optional_ping_data = NULL; | 386 ManifestFetchData::PingData* optional_ping_data = NULL; |
359 if (delegate_->GetPingDataForExtension(id, &ping_data)) | 387 if (delegate_->GetPingDataForExtension(id, &ping_data)) |
360 optional_ping_data = &ping_data; | 388 optional_ping_data = &ping_data; |
361 | 389 |
362 // Find or create a ManifestFetchData to add this extension to. | 390 // Find or create a ManifestFetchData to add this extension to. |
363 bool added = false; | 391 bool added = false; |
364 FetchMap::iterator existing_iter = fetches_preparing_.find( | 392 FetchMap::iterator existing_iter = fetches_preparing_.find( |
365 std::make_pair(request_id, update_urls[i])); | 393 std::make_pair(request_id, update_urls[i])); |
366 if (existing_iter != fetches_preparing_.end() && | 394 if (existing_iter != fetches_preparing_.end() && |
367 !existing_iter->second.empty()) { | 395 !existing_iter->second.empty()) { |
368 // Try to add to the ManifestFetchData at the end of the list. | 396 // Try to add to the ManifestFetchData at the end of the list. |
369 ManifestFetchData* existing_fetch = existing_iter->second.back().get(); | 397 ManifestFetchData* existing_fetch = existing_iter->second.back().get(); |
370 if (existing_fetch->AddExtension(id, version.GetString(), | 398 if (existing_fetch->AddExtension(id, version.GetString(), |
371 optional_ping_data, update_url_data, | 399 optional_ping_data, update_url_data, |
372 install_source)) { | 400 install_source, |
| 401 force_update)) { |
373 added = true; | 402 added = true; |
374 } | 403 } |
375 } | 404 } |
376 if (!added) { | 405 if (!added) { |
377 // Otherwise add a new element to the list, if the list doesn't exist or | 406 // Otherwise add a new element to the list, if the list doesn't exist or |
378 // if its last element is already full. | 407 // if its last element is already full. |
379 linked_ptr<ManifestFetchData> fetch( | 408 linked_ptr<ManifestFetchData> fetch( |
380 new ManifestFetchData(update_urls[i], request_id)); | 409 new ManifestFetchData(update_urls[i], request_id)); |
381 fetches_preparing_[std::make_pair(request_id, update_urls[i])]. | 410 fetches_preparing_[std::make_pair(request_id, update_urls[i])]. |
382 push_back(fetch); | 411 push_back(fetch); |
383 added = fetch->AddExtension(id, version.GetString(), | 412 added = fetch->AddExtension(id, version.GetString(), |
384 optional_ping_data, | 413 optional_ping_data, |
385 update_url_data, | 414 update_url_data, |
386 install_source); | 415 install_source, |
| 416 force_update); |
387 DCHECK(added); | 417 DCHECK(added); |
388 } | 418 } |
389 } | 419 } |
390 | 420 |
391 return true; | 421 return true; |
392 } | 422 } |
393 | 423 |
394 void ExtensionDownloader::ReportStats() const { | 424 void ExtensionDownloader::ReportStats() const { |
395 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", | 425 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", |
396 url_stats_.extension_count); | 426 url_stats_.extension_count); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 // version is the same or older than what's already installed, | 662 // version is the same or older than what's already installed, |
633 // we don't want it. | 663 // we don't want it. |
634 std::string version; | 664 std::string version; |
635 if (!delegate_->GetExtensionExistingVersion(id, &version)) { | 665 if (!delegate_->GetExtensionExistingVersion(id, &version)) { |
636 VLOG(2) << id << " is not installed"; | 666 VLOG(2) << id << " is not installed"; |
637 continue; | 667 continue; |
638 } | 668 } |
639 | 669 |
640 VLOG(2) << id << " is at '" << version << "'"; | 670 VLOG(2) << id << " is at '" << version << "'"; |
641 | 671 |
642 Version existing_version(version); | 672 // We should skip the version check if update was forced. |
643 Version update_version(update->version); | 673 if (!fetch_data.DidForceUpdate(id)) { |
644 | 674 Version existing_version(version); |
645 if (!update_version.IsValid() || | 675 Version update_version(update->version); |
646 update_version.CompareTo(existing_version) <= 0) { | 676 if (!update_version.IsValid() || |
647 continue; | 677 update_version.CompareTo(existing_version) <= 0) { |
| 678 continue; |
| 679 } |
648 } | 680 } |
649 } | 681 } |
650 | 682 |
651 // If the update specifies a browser minimum version, do we qualify? | 683 // If the update specifies a browser minimum version, do we qualify? |
652 if (update->browser_min_version.length() > 0) { | 684 if (update->browser_min_version.length() > 0) { |
653 // First determine the browser version if we haven't already. | 685 // First determine the browser version if we haven't already. |
654 if (!browser_version.IsValid()) { | 686 if (!browser_version.IsValid()) { |
655 chrome::VersionInfo version_info; | 687 chrome::VersionInfo version_info; |
656 if (version_info.is_valid()) | 688 if (version_info.is_valid()) |
657 browser_version = Version(version_info.Version()); | 689 browser_version = Version(version_info.Version()); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 | 954 |
923 void ExtensionDownloader::OnGetTokenFailure( | 955 void ExtensionDownloader::OnGetTokenFailure( |
924 const OAuth2TokenService::Request* request, | 956 const OAuth2TokenService::Request* request, |
925 const GoogleServiceAuthError& error) { | 957 const GoogleServiceAuthError& error) { |
926 // If we fail to get an access token, kick the pending fetch and let it fall | 958 // If we fail to get an access token, kick the pending fetch and let it fall |
927 // back on cookies. | 959 // back on cookies. |
928 extension_fetcher_->Start(); | 960 extension_fetcher_->Start(); |
929 } | 961 } |
930 | 962 |
931 } // namespace extensions | 963 } // namespace extensions |
OLD | NEW |