Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Side by Side Diff: chrome/browser/extensions/updater/extension_downloader.cc

Issue 434493002: OAuth2 support for Webstore downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove WebstoreOAuth2TokenProvider Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 13 matching lines...) Expand all
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 "content/public/browser/browser_thread.h" 31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_details.h" 32 #include "content/public/browser/notification_details.h"
33 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/notification_service.h"
34 #include "google_apis/gaia/identity_provider.h"
34 #include "net/base/backoff_entry.h" 35 #include "net/base/backoff_entry.h"
35 #include "net/base/load_flags.h" 36 #include "net/base/load_flags.h"
36 #include "net/base/net_errors.h" 37 #include "net/base/net_errors.h"
38 #include "net/http/http_request_headers.h"
39 #include "net/http/http_status_code.h"
37 #include "net/url_request/url_fetcher.h" 40 #include "net/url_request/url_fetcher.h"
38 #include "net/url_request/url_request_context_getter.h" 41 #include "net/url_request/url_request_context_getter.h"
39 #include "net/url_request/url_request_status.h" 42 #include "net/url_request/url_request_status.h"
40 43
41 using base::Time; 44 using base::Time;
42 using base::TimeDelta; 45 using base::TimeDelta;
43 using content::BrowserThread; 46 using content::BrowserThread;
44 47
45 namespace extensions { 48 namespace extensions {
46 49
(...skipping 27 matching lines...) Expand all
74 false, 77 false,
75 }; 78 };
76 79
77 const char kAuthUserQueryKey[] = "authuser"; 80 const char kAuthUserQueryKey[] = "authuser";
78 81
79 const int kMaxAuthUserValue = 10; 82 const int kMaxAuthUserValue = 10;
80 83
81 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; 84 const char kNotFromWebstoreInstallSource[] = "notfromwebstore";
82 const char kDefaultInstallSource[] = ""; 85 const char kDefaultInstallSource[] = "";
83 86
84 #define RETRY_HISTOGRAM(name, retry_count, url) \ 87 const char kGoogleDotCom[] = "google.com";
85 if ((url).DomainIs("google.com")) { \ 88 const char kTokenServiceConsumerId[] = "extension_downloader";
86 UMA_HISTOGRAM_CUSTOM_COUNTS( \ 89 const char kWebstoreOAuth2Scope[] =
87 "Extensions." name "RetryCountGoogleUrl", retry_count, 1, \ 90 "https://www.googleapis.com/auth/chromewebstore.readonly";
88 kMaxRetries, kMaxRetries+1); \ 91
89 } else { \ 92 #define RETRY_HISTOGRAM(name, retry_count, url) \
90 UMA_HISTOGRAM_CUSTOM_COUNTS( \ 93 if ((url).DomainIs(kGoogleDotCom)) { \
91 "Extensions." name "RetryCountOtherUrl", retry_count, 1, \ 94 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountGoogleUrl", \
92 kMaxRetries, kMaxRetries+1); \ 95 retry_count, \
93 } 96 1, \
97 kMaxRetries, \
98 kMaxRetries + 1); \
99 } else { \
100 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountOtherUrl", \
101 retry_count, \
102 1, \
103 kMaxRetries, \
104 kMaxRetries + 1); \
105 }
94 106
95 bool ShouldRetryRequest(const net::URLRequestStatus& status, 107 bool ShouldRetryRequest(const net::URLRequestStatus& status,
96 int response_code) { 108 int response_code) {
97 // Retry if the response code is a server error, or the request failed because 109 // Retry if the response code is a server error, or the request failed because
98 // of network errors as opposed to file errors. 110 // of network errors as opposed to file errors.
99 return ((response_code >= 500 && status.is_success()) || 111 return ((response_code >= 500 && status.is_success()) ||
100 status.status() == net::URLRequestStatus::FAILED); 112 status.status() == net::URLRequestStatus::FAILED);
101 } 113 }
102 114
103 bool ShouldRetryRequestWithCookies(const net::URLRequestStatus& status,
104 int response_code,
105 bool included_cookies) {
106 if (included_cookies)
107 return false;
108
109 if (status.status() == net::URLRequestStatus::CANCELED)
110 return true;
111
112 // Retry if a 401 or 403 is received.
113 return (status.status() == net::URLRequestStatus::SUCCESS &&
114 (response_code == 401 || response_code == 403));
115 }
116
117 bool ShouldRetryRequestWithNextUser(const net::URLRequestStatus& status,
118 int response_code,
119 bool included_cookies) {
120 // Retry if a 403 is received in response to a request including cookies.
121 // Note that receiving a 401 in response to a request which included cookies
122 // should indicate that the |authuser| index was out of bounds for the profile
123 // and therefore Chrome should NOT retry with another index.
124 return (status.status() == net::URLRequestStatus::SUCCESS &&
125 response_code == 403 && included_cookies);
126 }
127
128 // This parses and updates a URL query such that the value of the |authuser| 115 // This parses and updates a URL query such that the value of the |authuser|
129 // query parameter is incremented by 1. If parameter was not present in the URL, 116 // query parameter is incremented by 1. If parameter was not present in the URL,
130 // it will be added with a value of 1. All other query keys and values are 117 // it will be added with a value of 1. All other query keys and values are
131 // preserved as-is. Returns |false| if the user index exceeds a hard-coded 118 // preserved as-is. Returns |false| if the user index exceeds a hard-coded
132 // maximum. 119 // maximum.
133 bool IncrementAuthUserIndex(GURL* url) { 120 bool IncrementAuthUserIndex(GURL* url) {
134 int user_index = 0; 121 int user_index = 0;
135 std::string old_query = url->query(); 122 std::string old_query = url->query();
136 std::vector<std::string> new_query_parts; 123 std::vector<std::string> new_query_parts;
137 url::Component query(0, old_query.length()); 124 url::Component query(0, old_query.length());
(...skipping 21 matching lines...) Expand all
159 } 146 }
160 147
161 } // namespace 148 } // namespace
162 149
163 UpdateDetails::UpdateDetails(const std::string& id, const Version& version) 150 UpdateDetails::UpdateDetails(const std::string& id, const Version& version)
164 : id(id), version(version) {} 151 : id(id), version(version) {}
165 152
166 UpdateDetails::~UpdateDetails() {} 153 UpdateDetails::~UpdateDetails() {}
167 154
168 ExtensionDownloader::ExtensionFetch::ExtensionFetch() 155 ExtensionDownloader::ExtensionFetch::ExtensionFetch()
169 : url(), is_protected(false) {} 156 : url(), credentials(CREDENTIALS_NONE) {
157 }
170 158
171 ExtensionDownloader::ExtensionFetch::ExtensionFetch( 159 ExtensionDownloader::ExtensionFetch::ExtensionFetch(
172 const std::string& id, 160 const std::string& id,
173 const GURL& url, 161 const GURL& url,
174 const std::string& package_hash, 162 const std::string& package_hash,
175 const std::string& version, 163 const std::string& version,
176 const std::set<int>& request_ids) 164 const std::set<int>& request_ids)
177 : id(id), url(url), package_hash(package_hash), version(version), 165 : id(id),
178 request_ids(request_ids), is_protected(false) {} 166 url(url),
167 package_hash(package_hash),
168 version(version),
169 request_ids(request_ids),
170 credentials(CREDENTIALS_NONE) {
171 }
179 172
180 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {} 173 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {}
181 174
182 ExtensionDownloader::ExtensionDownloader( 175 ExtensionDownloader::ExtensionDownloader(
183 ExtensionDownloaderDelegate* delegate, 176 ExtensionDownloaderDelegate* delegate,
184 net::URLRequestContextGetter* request_context) 177 net::URLRequestContextGetter* request_context,
185 : delegate_(delegate), 178 IdentityProvider* webstore_identity_provider)
179 : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
180 delegate_(delegate),
186 request_context_(request_context), 181 request_context_(request_context),
187 weak_ptr_factory_(this), 182 weak_ptr_factory_(this),
188 manifests_queue_(&kDefaultBackoffPolicy, 183 manifests_queue_(&kDefaultBackoffPolicy,
189 base::Bind(&ExtensionDownloader::CreateManifestFetcher, 184 base::Bind(&ExtensionDownloader::CreateManifestFetcher,
190 base::Unretained(this))), 185 base::Unretained(this))),
191 extensions_queue_(&kDefaultBackoffPolicy, 186 extensions_queue_(&kDefaultBackoffPolicy,
192 base::Bind(&ExtensionDownloader::CreateExtensionFetcher, 187 base::Bind(&ExtensionDownloader::CreateExtensionFetcher,
193 base::Unretained(this))), 188 base::Unretained(this))),
194 extension_cache_(NULL) { 189 extension_cache_(NULL),
190 identity_provider_(webstore_identity_provider) {
195 DCHECK(delegate_); 191 DCHECK(delegate_);
196 DCHECK(request_context_); 192 DCHECK(request_context_);
197 } 193 }
198 194
199 ExtensionDownloader::~ExtensionDownloader() {} 195 ExtensionDownloader::~ExtensionDownloader() {}
200 196
201 bool ExtensionDownloader::AddExtension(const Extension& extension, 197 bool ExtensionDownloader::AddExtension(const Extension& extension,
202 int request_id) { 198 int request_id) {
203 // Skip extensions with empty update URLs converted from user 199 // Skip extensions with empty update URLs converted from user
204 // scripts. 200 // scripts.
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 if (extension_urls::IsWebstoreUpdateUrl(update_url) && 295 if (extension_urls::IsWebstoreUpdateUrl(update_url) &&
300 !update_url.SchemeIsSecure()) 296 !update_url.SchemeIsSecure())
301 update_url = extension_urls::GetWebstoreUpdateUrl(); 297 update_url = extension_urls::GetWebstoreUpdateUrl();
302 298
303 // Skip extensions with empty IDs. 299 // Skip extensions with empty IDs.
304 if (id.empty()) { 300 if (id.empty()) {
305 LOG(WARNING) << "Found extension with empty ID"; 301 LOG(WARNING) << "Found extension with empty ID";
306 return false; 302 return false;
307 } 303 }
308 304
309 if (update_url.DomainIs("google.com")) { 305 if (update_url.DomainIs(kGoogleDotCom)) {
310 url_stats_.google_url_count++; 306 url_stats_.google_url_count++;
311 } else if (update_url.is_empty()) { 307 } else if (update_url.is_empty()) {
312 url_stats_.no_url_count++; 308 url_stats_.no_url_count++;
313 // Fill in default update URL. 309 // Fill in default update URL.
314 update_url = extension_urls::GetWebstoreUpdateUrl(); 310 update_url = extension_urls::GetWebstoreUpdateUrl();
315 } else { 311 } else {
316 url_stats_.other_url_count++; 312 url_stats_.other_url_count++;
317 } 313 }
318 314
319 switch (extension_type) { 315 switch (extension_type) {
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 } 569 }
574 } 570 }
575 scoped_ptr<ExtensionFetch> fetch(new ExtensionFetch( 571 scoped_ptr<ExtensionFetch> fetch(new ExtensionFetch(
576 update->extension_id, crx_url, update->package_hash, 572 update->extension_id, crx_url, update->package_hash,
577 update->version, fetch_data.request_ids())); 573 update->version, fetch_data.request_ids()));
578 FetchUpdatedExtension(fetch.Pass()); 574 FetchUpdatedExtension(fetch.Pass());
579 } 575 }
580 576
581 // If the manifest response included a <daystart> element, we want to save 577 // If the manifest response included a <daystart> element, we want to save
582 // that value for any extensions which had sent a ping in the request. 578 // that value for any extensions which had sent a ping in the request.
583 if (fetch_data.base_url().DomainIs("google.com") && 579 if (fetch_data.base_url().DomainIs(kGoogleDotCom) &&
584 results->daystart_elapsed_seconds >= 0) { 580 results->daystart_elapsed_seconds >= 0) {
585 Time day_start = 581 Time day_start =
586 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); 582 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds);
587 583
588 const std::set<std::string>& extension_ids = fetch_data.extension_ids(); 584 const std::set<std::string>& extension_ids = fetch_data.extension_ids();
589 std::set<std::string>::const_iterator i; 585 std::set<std::string>::const_iterator i;
590 for (i = extension_ids.begin(); i != extension_ids.end(); i++) { 586 for (i = extension_ids.begin(); i != extension_ids.end(); i++) {
591 const std::string& id = *i; 587 const std::string& id = *i;
592 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id]; 588 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id];
593 result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL); 589 result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 const base::FilePath& crx_path, 711 const base::FilePath& crx_path,
716 bool file_ownership_passed) { 712 bool file_ownership_passed) {
717 delegate_->OnExtensionDownloadFinished(fetch_data->id, crx_path, 713 delegate_->OnExtensionDownloadFinished(fetch_data->id, crx_path,
718 file_ownership_passed, fetch_data->url, fetch_data->version, 714 file_ownership_passed, fetch_data->url, fetch_data->version,
719 ping_results_[fetch_data->id], fetch_data->request_ids); 715 ping_results_[fetch_data->id], fetch_data->request_ids);
720 ping_results_.erase(fetch_data->id); 716 ping_results_.erase(fetch_data->id);
721 } 717 }
722 718
723 void ExtensionDownloader::CreateExtensionFetcher() { 719 void ExtensionDownloader::CreateExtensionFetcher() {
724 const ExtensionFetch* fetch = extensions_queue_.active_request(); 720 const ExtensionFetch* fetch = extensions_queue_.active_request();
721 extension_fetcher_.reset(net::URLFetcher::Create(
722 kExtensionFetcherId, fetch->url, net::URLFetcher::GET, this));
723 extension_fetcher_->SetRequestContext(request_context_);
724 extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
725
725 int load_flags = net::LOAD_DISABLE_CACHE; 726 int load_flags = net::LOAD_DISABLE_CACHE;
726 if (!fetch->is_protected || !fetch->url.SchemeIs("https")) { 727 bool is_secure = fetch->url.SchemeIsSecure();
728 if (fetch->credentials != ExtensionFetch::CREDENTIALS_COOKIES || !is_secure) {
727 load_flags |= net::LOAD_DO_NOT_SEND_COOKIES | 729 load_flags |= net::LOAD_DO_NOT_SEND_COOKIES |
728 net::LOAD_DO_NOT_SAVE_COOKIES; 730 net::LOAD_DO_NOT_SAVE_COOKIES;
729 } 731 }
730 extension_fetcher_.reset(net::URLFetcher::Create(
731 kExtensionFetcherId, fetch->url, net::URLFetcher::GET, this));
732 extension_fetcher_->SetRequestContext(request_context_);
733 extension_fetcher_->SetLoadFlags(load_flags); 732 extension_fetcher_->SetLoadFlags(load_flags);
734 extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); 733
735 // Download CRX files to a temp file. The blacklist is small and will be 734 // Download CRX files to a temp file. The blacklist is small and will be
736 // processed in memory, so it is fetched into a string. 735 // processed in memory, so it is fetched into a string.
737 if (fetch->id != kBlacklistAppID) { 736 if (fetch->id != kBlacklistAppID) {
738 extension_fetcher_->SaveResponseToTemporaryFile( 737 extension_fetcher_->SaveResponseToTemporaryFile(
739 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); 738 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
740 } 739 }
741 740
741 if (fetch->credentials == ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN &&
742 is_secure) {
743 if (access_token_.empty()) {
744 // We should try OAuth2, but we have no token cached. This
745 // ExtensionFetcher will be started once a token fetch is complete.
746 DCHECK(identity_provider_);
747 OAuth2TokenService::ScopeSet webstore_scopes;
748 webstore_scopes.insert(kWebstoreOAuth2Scope);
749 access_token_request_ =
750 identity_provider_->GetTokenService()->StartRequest(
751 identity_provider_->GetActiveAccountId(),
752 webstore_scopes,
753 this);
asargent_no_longer_on_chrome 2014/08/07 17:09:12 It might be helpful to future readers to add a com
Ken Rockot(use gerrit already) 2014/08/07 19:50:47 Added some clarity to the existing comment
754 return;
755 }
756 extension_fetcher_->AddExtraRequestHeader(
757 base::StringPrintf("%s: Bearer %s",
758 net::HttpRequestHeaders::kAuthorization,
759 access_token_.c_str()));
asargent_no_longer_on_chrome 2014/08/07 17:09:12 Would it be worth adding a kAuthorizationBearer co
Ken Rockot(use gerrit already) 2014/08/07 19:50:47 Bearer tokens are (unlike the Authorization header
760 }
761
742 VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id; 762 VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id;
743
744 extension_fetcher_->Start(); 763 extension_fetcher_->Start();
745 } 764 }
746 765
747 void ExtensionDownloader::OnCRXFetchComplete( 766 void ExtensionDownloader::OnCRXFetchComplete(
748 const net::URLFetcher* source, 767 const net::URLFetcher* source,
749 const GURL& url, 768 const GURL& url,
750 const net::URLRequestStatus& status, 769 const net::URLRequestStatus& status,
751 int response_code, 770 int response_code,
752 const base::TimeDelta& backoff_delay) { 771 const base::TimeDelta& backoff_delay) {
753 const std::string& id = extensions_queue_.active_request()->id; 772 ExtensionFetch& active_request = *extensions_queue_.active_request();
773 const std::string& id = active_request.id;
754 if (status.status() == net::URLRequestStatus::SUCCESS && 774 if (status.status() == net::URLRequestStatus::SUCCESS &&
755 (response_code == 200 || url.SchemeIsFile())) { 775 (response_code == 200 || url.SchemeIsFile())) {
756 RETRY_HISTOGRAM("CrxFetchSuccess", 776 RETRY_HISTOGRAM("CrxFetchSuccess",
757 extensions_queue_.active_request_failure_count(), url); 777 extensions_queue_.active_request_failure_count(), url);
758 base::FilePath crx_path; 778 base::FilePath crx_path;
759 // Take ownership of the file at |crx_path|. 779 // Take ownership of the file at |crx_path|.
760 CHECK(source->GetResponseAsFilePath(true, &crx_path)); 780 CHECK(source->GetResponseAsFilePath(true, &crx_path));
761 scoped_ptr<ExtensionFetch> fetch_data = 781 scoped_ptr<ExtensionFetch> fetch_data =
762 extensions_queue_.reset_active_request(); 782 extensions_queue_.reset_active_request();
763 if (extension_cache_) { 783 if (extension_cache_) {
764 const std::string& version = fetch_data->version; 784 const std::string& version = fetch_data->version;
765 extension_cache_->PutExtension(id, crx_path, version, 785 extension_cache_->PutExtension(id, crx_path, version,
766 base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished, 786 base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished,
767 weak_ptr_factory_.GetWeakPtr(), 787 weak_ptr_factory_.GetWeakPtr(),
768 base::Passed(&fetch_data))); 788 base::Passed(&fetch_data)));
769 } else { 789 } else {
770 NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, true); 790 NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, true);
771 } 791 }
772 } else if (ShouldRetryRequestWithCookies( 792 } else if (IterateFetchCredentialsAfterFailure(
773 status, 793 &active_request,
774 response_code, 794 status,
775 extensions_queue_.active_request()->is_protected)) { 795 response_code)) {
776 // Requeue the fetch with |is_protected| set, enabling cookies.
777 extensions_queue_.active_request()->is_protected = true;
778 extensions_queue_.RetryRequest(backoff_delay);
779 } else if (ShouldRetryRequestWithNextUser(
780 status,
781 response_code,
782 extensions_queue_.active_request()->is_protected) &&
783 IncrementAuthUserIndex(&extensions_queue_.active_request()->url)) {
784 extensions_queue_.RetryRequest(backoff_delay); 796 extensions_queue_.RetryRequest(backoff_delay);
785 } else { 797 } else {
786 const std::set<int>& request_ids = 798 const std::set<int>& request_ids = active_request.request_ids;
787 extensions_queue_.active_request()->request_ids;
788 const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id]; 799 const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id];
789 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() 800 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
790 << "' response code:" << response_code; 801 << "' response code:" << response_code;
791 if (ShouldRetryRequest(status, response_code) && 802 if (ShouldRetryRequest(status, response_code) &&
792 extensions_queue_.active_request_failure_count() < kMaxRetries) { 803 extensions_queue_.active_request_failure_count() < kMaxRetries) {
793 extensions_queue_.RetryRequest(backoff_delay); 804 extensions_queue_.RetryRequest(backoff_delay);
794 } else { 805 } else {
795 RETRY_HISTOGRAM("CrxFetchFailure", 806 RETRY_HISTOGRAM("CrxFetchFailure",
796 extensions_queue_.active_request_failure_count(), url); 807 extensions_queue_.active_request_failure_count(), url);
797 // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h) 808 // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h)
(...skipping 25 matching lines...) Expand all
823 834
824 void ExtensionDownloader::NotifyUpdateFound(const std::string& id, 835 void ExtensionDownloader::NotifyUpdateFound(const std::string& id,
825 const std::string& version) { 836 const std::string& version) {
826 UpdateDetails updateInfo(id, Version(version)); 837 UpdateDetails updateInfo(id, Version(version));
827 content::NotificationService::current()->Notify( 838 content::NotificationService::current()->Notify(
828 extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND, 839 extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND,
829 content::NotificationService::AllBrowserContextsAndSources(), 840 content::NotificationService::AllBrowserContextsAndSources(),
830 content::Details<UpdateDetails>(&updateInfo)); 841 content::Details<UpdateDetails>(&updateInfo));
831 } 842 }
832 843
844 bool ExtensionDownloader::IterateFetchCredentialsAfterFailure(
845 ExtensionFetch* fetch,
846 const net::URLRequestStatus& status,
847 int response_code) {
848 bool auth_failure = status.status() == net::URLRequestStatus::CANCELED ||
849 (status.status() == net::URLRequestStatus::SUCCESS &&
850 (response_code == net::HTTP_UNAUTHORIZED ||
851 response_code == net::HTTP_FORBIDDEN));
852 if (!auth_failure) {
853 return false;
854 }
855 // Here we decide what to do next if the server refused to authorize this
856 // fetch.
857 switch (fetch->credentials) {
858 case ExtensionFetch::CREDENTIALS_NONE:
859 if (fetch->url.DomainIs(kGoogleDotCom) && identity_provider_) {
860 fetch->credentials = ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN;
861 } else {
862 fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
863 }
864 return true;
865 case ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN:
866 // OAuth2 may fail due to an expired access token, in which case we
867 // should invalidate the token and try again.
868 if (response_code == net::HTTP_UNAUTHORIZED) {
869 DCHECK(identity_provider_ != NULL);
870 OAuth2TokenService::ScopeSet webstore_scopes;
871 webstore_scopes.insert(kWebstoreOAuth2Scope);
872 identity_provider_->GetTokenService()->InvalidateToken(
873 identity_provider_->GetActiveAccountId(),
874 webstore_scopes,
875 access_token_);
876 access_token_.clear();
asargent_no_longer_on_chrome 2014/08/07 17:09:12 Can a misbehaving server cause us to fall into an
Ken Rockot(use gerrit already) 2014/08/07 19:50:48 Ah yes. Good catch. Added an attempt counter to th
877 return true;
878 }
879 // Either there is no Gaia identity available or the active identity
880 // doesn't have access to this resource. Fall back on cookies.
881 if (access_token_.empty() ||
882 response_code == net::HTTP_FORBIDDEN) {
883 fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
884 return true;
885 }
886 return false;
887 case ExtensionFetch::CREDENTIALS_COOKIES:
888 if (response_code == net::HTTP_FORBIDDEN) {
889 // Try the next session identity, up to some maximum.
890 return IncrementAuthUserIndex(&fetch->url);
891 }
892 return false;
893 default:
894 NOTREACHED();
895 }
896 NOTREACHED();
897 }
898
899 void ExtensionDownloader::OnGetTokenSuccess(
900 const OAuth2TokenService::Request* request,
901 const std::string& access_token,
902 const base::Time& expiration_time) {
903 access_token_ = access_token;
904 extension_fetcher_->AddExtraRequestHeader(
905 base::StringPrintf("%s: Bearer %s",
906 net::HttpRequestHeaders::kAuthorization,
907 access_token_.c_str()));
908 extension_fetcher_->Start();
909 }
910
911 void ExtensionDownloader::OnGetTokenFailure(
912 const OAuth2TokenService::Request* request,
913 const GoogleServiceAuthError& error) {
914 // If we fail to get an access token, kick the pending fetch and let it fall
915 // back on cookies.
916 extension_fetcher_->Start();
917 }
918
833 } // namespace extensions 919 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/updater/extension_downloader.h ('k') | chrome/browser/extensions/updater/extension_updater.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698