Chromium Code Reviews| 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 return false; | 143 return false; |
| 144 } | 144 } |
| 145 | 145 |
| 146 // If the extension updates itself from the gallery, ignore any update URL | 146 // If the extension updates itself from the gallery, ignore any update URL |
| 147 // data. At the moment there is no extra data that an extension can | 147 // data. At the moment there is no extra data that an extension can |
| 148 // communicate to the the gallery update servers. | 148 // communicate to the the gallery update servers. |
| 149 std::string update_url_data; | 149 std::string update_url_data; |
| 150 if (!extension.UpdatesFromGallery()) | 150 if (!extension.UpdatesFromGallery()) |
| 151 update_url_data = delegate_->GetUpdateUrlData(extension.id()); | 151 update_url_data = delegate_->GetUpdateUrlData(extension.id()); |
| 152 | 152 |
| 153 // Make sure we use SSL for store-hosted extensions. | |
| 154 GURL update_url = extension.update_url(); | |
| 155 if (extension.UpdatesFromGallery() && !update_url.SchemeIsSecure()) | |
| 156 update_url = extension_urls::GetWebstoreUpdateUrl(); | |
| 157 | |
| 153 return AddExtensionData(extension.id(), *extension.version(), | 158 return AddExtensionData(extension.id(), *extension.version(), |
| 154 extension.GetType(), extension.update_url(), | 159 extension.GetType(), update_url, |
| 155 update_url_data); | 160 update_url_data); |
| 156 } | 161 } |
| 157 | 162 |
| 158 bool ExtensionDownloader::AddPendingExtension(const std::string& id, | 163 bool ExtensionDownloader::AddPendingExtension(const std::string& id, |
| 159 const GURL& update_url) { | 164 const GURL& update_url) { |
| 160 // Use a zero version to ensure that a pending extension will always | 165 // Use a zero version to ensure that a pending extension will always |
| 161 // be updated, and thus installed (assuming all extensions have | 166 // be updated, and thus installed (assuming all extensions have |
| 162 // non-zero versions). | 167 // non-zero versions). |
| 163 Version version("0.0.0.0"); | 168 Version version("0.0.0.0"); |
| 164 DCHECK(version.IsValid()); | 169 DCHECK(version.IsValid()); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 180 fetches_preparing_.clear(); | 185 fetches_preparing_.clear(); |
| 181 } | 186 } |
| 182 | 187 |
| 183 void ExtensionDownloader::StartBlacklistUpdate( | 188 void ExtensionDownloader::StartBlacklistUpdate( |
| 184 const std::string& version, | 189 const std::string& version, |
| 185 const ManifestFetchData::PingData& ping_data) { | 190 const ManifestFetchData::PingData& ping_data) { |
| 186 // Note: it is very important that we use the https version of the update | 191 // Note: it is very important that we use the https version of the update |
| 187 // url here to avoid DNS hijacking of the blacklist, which is not validated | 192 // url here to avoid DNS hijacking of the blacklist, which is not validated |
| 188 // by a public key signature like .crx files are. | 193 // by a public key signature like .crx files are. |
| 189 ManifestFetchData* blacklist_fetch = | 194 ManifestFetchData* blacklist_fetch = |
| 190 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl(true)); | 195 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl()); |
| 196 DCHECK(blacklist_fetch->base_url().SchemeIsSecure()); | |
| 191 blacklist_fetch->AddExtension(kBlacklistAppID, version, &ping_data, "", | 197 blacklist_fetch->AddExtension(kBlacklistAppID, version, &ping_data, "", |
| 192 kDefaultInstallSource); | 198 kDefaultInstallSource); |
| 193 StartUpdateCheck(blacklist_fetch); | 199 StartUpdateCheck(blacklist_fetch); |
| 194 } | 200 } |
| 195 | 201 |
| 196 bool ExtensionDownloader::AddExtensionData(const std::string& id, | 202 bool ExtensionDownloader::AddExtensionData(const std::string& id, |
| 197 const Version& version, | 203 const Version& version, |
| 198 Extension::Type extension_type, | 204 Extension::Type extension_type, |
| 199 GURL update_url, | 205 GURL update_url, |
| 200 const std::string& update_url_data) { | 206 const std::string& update_url_data) { |
| 201 // Skip extensions with non-empty invalid update URLs. | 207 // Skip extensions with non-empty invalid update URLs. |
| 202 if (!update_url.is_empty() && !update_url.is_valid()) { | 208 if (!update_url.is_empty() && !update_url.is_valid()) { |
| 203 LOG(WARNING) << "Extension " << id << " has invalid update url " | 209 LOG(WARNING) << "Extension " << id << " has invalid update url " |
| 204 << update_url; | 210 << update_url; |
| 205 return false; | 211 return false; |
| 206 } | 212 } |
| 207 | 213 |
| 214 // Double-check that we're using https for webstore urls. | |
| 215 if (extension_urls::IsWebstoreUpdateUrl(update_url) && | |
| 216 !update_url.SchemeIsSecure() && | |
| 217 extension_urls::GetWebstoreUpdateUrl().SchemeIsSecure()) { | |
| 218 NOTREACHED() << "Refusing to send non-secure update check for " << id | |
| 219 << " (" << update_url.spec() << ")"; | |
| 220 return false; | |
| 221 } | |
| 222 | |
| 208 // Skip extensions with empty IDs. | 223 // Skip extensions with empty IDs. |
| 209 if (id.empty()) { | 224 if (id.empty()) { |
| 210 LOG(WARNING) << "Found extension with empty ID"; | 225 LOG(WARNING) << "Found extension with empty ID"; |
| 211 return false; | 226 return false; |
| 212 } | 227 } |
| 213 | 228 |
| 214 if (update_url.DomainIs("google.com")) { | 229 if (update_url.DomainIs("google.com")) { |
| 215 url_stats_.google_url_count++; | 230 url_stats_.google_url_count++; |
| 216 } else if (update_url.is_empty()) { | 231 } else if (update_url.is_empty()) { |
| 217 url_stats_.no_url_count++; | 232 url_stats_.no_url_count++; |
| 218 // Fill in default update URL. | 233 // Fill in default update URL. |
| 219 // | 234 update_url = extension_urls::GetWebstoreUpdateUrl(); |
| 220 // TODO(akalin): Figure out if we should use the HTTPS version. | |
| 221 update_url = extension_urls::GetWebstoreUpdateUrl(false); | |
| 222 } else { | 235 } else { |
| 223 url_stats_.other_url_count++; | 236 url_stats_.other_url_count++; |
| 224 } | 237 } |
| 225 | 238 |
| 226 switch (extension_type) { | 239 switch (extension_type) { |
| 227 case Extension::TYPE_THEME: | 240 case Extension::TYPE_THEME: |
| 228 ++url_stats_.theme_count; | 241 ++url_stats_.theme_count; |
| 229 break; | 242 break; |
| 230 case Extension::TYPE_EXTENSION: | 243 case Extension::TYPE_EXTENSION: |
| 231 case Extension::TYPE_USER_SCRIPT: | 244 case Extension::TYPE_USER_SCRIPT: |
| 232 ++url_stats_.extension_count; | 245 ++url_stats_.extension_count; |
| 233 break; | 246 break; |
| 234 case Extension::TYPE_HOSTED_APP: | 247 case Extension::TYPE_HOSTED_APP: |
| 235 case Extension::TYPE_PACKAGED_APP: | 248 case Extension::TYPE_PACKAGED_APP: |
| 236 ++url_stats_.app_count; | 249 ++url_stats_.app_count; |
| 237 break; | 250 break; |
| 238 case Extension::TYPE_UNKNOWN: | 251 case Extension::TYPE_UNKNOWN: |
| 239 default: | 252 default: |
| 240 ++url_stats_.pending_count; | 253 ++url_stats_.pending_count; |
| 241 break; | 254 break; |
| 242 } | 255 } |
| 243 | 256 |
| 244 std::vector<GURL> update_urls; | 257 std::vector<GURL> update_urls; |
| 245 update_urls.push_back(update_url); | 258 update_urls.push_back(update_url); |
| 246 // If UMA is enabled, also add to ManifestFetchData for the | 259 // If UMA is enabled, also add to ManifestFetchData for the |
| 247 // webstore update URL. | 260 // webstore update URL. |
| 248 if (!extension_urls::IsWebstoreUpdateUrl(update_url) && | 261 if (!extension_urls::IsWebstoreUpdateUrl(update_url) && |
| 249 MetricsServiceHelper::IsMetricsReportingEnabled()) { | 262 MetricsServiceHelper::IsMetricsReportingEnabled()) { |
| 250 update_urls.push_back(extension_urls::GetWebstoreUpdateUrl(false)); | 263 update_urls.push_back(extension_urls::GetWebstoreUpdateUrl()); |
| 251 } | 264 } |
| 252 | 265 |
| 253 for (size_t i = 0; i < update_urls.size(); ++i) { | 266 for (size_t i = 0; i < update_urls.size(); ++i) { |
| 254 DCHECK(!update_urls[i].is_empty()); | 267 DCHECK(!update_urls[i].is_empty()); |
| 255 DCHECK(update_urls[i].is_valid()); | 268 DCHECK(update_urls[i].is_valid()); |
| 256 | 269 |
| 257 std::string install_source = i == 0 ? | 270 std::string install_source = i == 0 ? |
| 258 kDefaultInstallSource : kNotFromWebstoreInstallSource; | 271 kDefaultInstallSource : kNotFromWebstoreInstallSource; |
| 259 | 272 |
| 260 ManifestFetchData::PingData ping_data; | 273 ManifestFetchData::PingData ping_data; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 return; | 438 return; |
| 426 } | 439 } |
| 427 | 440 |
| 428 // Examine the parsed manifest and kick off fetches of any new crx files. | 441 // Examine the parsed manifest and kick off fetches of any new crx files. |
| 429 std::vector<int> updates; | 442 std::vector<int> updates; |
| 430 DetermineUpdates(fetch_data, *results, &updates); | 443 DetermineUpdates(fetch_data, *results, &updates); |
| 431 for (size_t i = 0; i < updates.size(); i++) { | 444 for (size_t i = 0; i < updates.size(); i++) { |
| 432 const UpdateManifest::Result* update = &(results->list.at(updates[i])); | 445 const UpdateManifest::Result* update = &(results->list.at(updates[i])); |
| 433 const std::string& id = update->extension_id; | 446 const std::string& id = update->extension_id; |
| 434 not_updated.erase(id); | 447 not_updated.erase(id); |
| 448 | |
| 449 GURL crx_url = update->crx_url; | |
| 435 if (id != kBlacklistAppID) { | 450 if (id != kBlacklistAppID) { |
| 436 NotifyUpdateFound(update->extension_id); | 451 NotifyUpdateFound(update->extension_id); |
| 437 } else { | 452 } else { |
| 438 // The URL of the blacklist file is returned by the server and we need to | 453 // The URL of the blacklist file is returned by the server and we need to |
| 439 // be sure that we continue to be able to reliably detect whether a URL | 454 // be sure that we continue to be able to reliably detect whether a URL |
| 440 // references a blacklist file. | 455 // references a blacklist file. |
| 441 DCHECK(extension_urls::IsBlacklistUpdateUrl(update->crx_url)) | 456 DCHECK(extension_urls::IsBlacklistUpdateUrl(crx_url)) << crx_url; |
| 442 << update->crx_url; | 457 |
| 458 // Force https (crbug.com/129587). | |
| 459 if (!crx_url.SchemeIsSecure()) { | |
|
Aaron Boodman
2012/05/24 23:17:41
Will this affect non-store updates?
asargent_no_longer_on_chrome
2012/05/24 23:23:53
No, this is in the else block for the "if (id != k
| |
| 460 url_canon::Replacements<char> replacements; | |
| 461 std::string scheme("https"); | |
| 462 replacements.SetScheme(scheme.c_str(), | |
| 463 url_parse::Component(0, scheme.size())); | |
| 464 crx_url = crx_url.ReplaceComponents(replacements); | |
| 465 } | |
| 443 } | 466 } |
| 444 FetchUpdatedExtension(update->extension_id, update->crx_url, | 467 FetchUpdatedExtension(update->extension_id, crx_url, update->package_hash, |
| 445 update->package_hash, update->version); | 468 update->version); |
| 446 } | 469 } |
| 447 | 470 |
| 448 // If the manifest response included a <daystart> element, we want to save | 471 // If the manifest response included a <daystart> element, we want to save |
| 449 // that value for any extensions which had sent a ping in the request. | 472 // that value for any extensions which had sent a ping in the request. |
| 450 if (fetch_data.base_url().DomainIs("google.com") && | 473 if (fetch_data.base_url().DomainIs("google.com") && |
| 451 results->daystart_elapsed_seconds >= 0) { | 474 results->daystart_elapsed_seconds >= 0) { |
| 452 Time day_start = | 475 Time day_start = |
| 453 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); | 476 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); |
| 454 | 477 |
| 455 const std::set<std::string>& extension_ids = fetch_data.extension_ids(); | 478 const std::set<std::string>& extension_ids = fetch_data.extension_ids(); |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 } | 665 } |
| 643 | 666 |
| 644 void ExtensionDownloader::NotifyUpdateFound(const std::string& id) { | 667 void ExtensionDownloader::NotifyUpdateFound(const std::string& id) { |
| 645 content::NotificationService::current()->Notify( | 668 content::NotificationService::current()->Notify( |
| 646 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, | 669 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, |
| 647 content::NotificationService::AllBrowserContextsAndSources(), | 670 content::NotificationService::AllBrowserContextsAndSources(), |
| 648 content::Details<const std::string>(&id)); | 671 content::Details<const std::string>(&id)); |
| 649 } | 672 } |
| 650 | 673 |
| 651 } // namespace extensions | 674 } // namespace extensions |
| OLD | NEW |