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

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: fix ExternalCache on chromeos 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 23 matching lines...) Expand all
70 // has no significant state, -1 to never discard. 73 // has no significant state, -1 to never discard.
71 -1, 74 -1,
72 75
73 // Don't use initial delay unless the last request was an error. 76 // Don't use initial delay unless the last request was an error.
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;
83 const int kMaxOAuth2Attempts = 3;
80 84
81 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; 85 const char kNotFromWebstoreInstallSource[] = "notfromwebstore";
82 const char kDefaultInstallSource[] = ""; 86 const char kDefaultInstallSource[] = "";
83 87
84 #define RETRY_HISTOGRAM(name, retry_count, url) \ 88 const char kGoogleDotCom[] = "google.com";
85 if ((url).DomainIs("google.com")) { \ 89 const char kTokenServiceConsumerId[] = "extension_downloader";
86 UMA_HISTOGRAM_CUSTOM_COUNTS( \ 90 const char kWebstoreOAuth2Scope[] =
87 "Extensions." name "RetryCountGoogleUrl", retry_count, 1, \ 91 "https://www.googleapis.com/auth/chromewebstore.readonly";
88 kMaxRetries, kMaxRetries+1); \ 92
89 } else { \ 93 #define RETRY_HISTOGRAM(name, retry_count, url) \
90 UMA_HISTOGRAM_CUSTOM_COUNTS( \ 94 if ((url).DomainIs(kGoogleDotCom)) { \
91 "Extensions." name "RetryCountOtherUrl", retry_count, 1, \ 95 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountGoogleUrl", \
92 kMaxRetries, kMaxRetries+1); \ 96 retry_count, \
93 } 97 1, \
98 kMaxRetries, \
99 kMaxRetries + 1); \
100 } else { \
101 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountOtherUrl", \
102 retry_count, \
103 1, \
104 kMaxRetries, \
105 kMaxRetries + 1); \
106 }
94 107
95 bool ShouldRetryRequest(const net::URLRequestStatus& status, 108 bool ShouldRetryRequest(const net::URLRequestStatus& status,
96 int response_code) { 109 int response_code) {
97 // Retry if the response code is a server error, or the request failed because 110 // Retry if the response code is a server error, or the request failed because
98 // of network errors as opposed to file errors. 111 // of network errors as opposed to file errors.
99 return ((response_code >= 500 && status.is_success()) || 112 return ((response_code >= 500 && status.is_success()) ||
100 status.status() == net::URLRequestStatus::FAILED); 113 status.status() == net::URLRequestStatus::FAILED);
101 } 114 }
102 115
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| 116 // 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, 117 // 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 118 // 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 119 // preserved as-is. Returns |false| if the user index exceeds a hard-coded
132 // maximum. 120 // maximum.
133 bool IncrementAuthUserIndex(GURL* url) { 121 bool IncrementAuthUserIndex(GURL* url) {
134 int user_index = 0; 122 int user_index = 0;
135 std::string old_query = url->query(); 123 std::string old_query = url->query();
136 std::vector<std::string> new_query_parts; 124 std::vector<std::string> new_query_parts;
137 url::Component query(0, old_query.length()); 125 url::Component query(0, old_query.length());
(...skipping 21 matching lines...) Expand all
159 } 147 }
160 148
161 } // namespace 149 } // namespace
162 150
163 UpdateDetails::UpdateDetails(const std::string& id, const Version& version) 151 UpdateDetails::UpdateDetails(const std::string& id, const Version& version)
164 : id(id), version(version) {} 152 : id(id), version(version) {}
165 153
166 UpdateDetails::~UpdateDetails() {} 154 UpdateDetails::~UpdateDetails() {}
167 155
168 ExtensionDownloader::ExtensionFetch::ExtensionFetch() 156 ExtensionDownloader::ExtensionFetch::ExtensionFetch()
169 : url(), is_protected(false) {} 157 : url(), credentials(CREDENTIALS_NONE) {
158 }
170 159
171 ExtensionDownloader::ExtensionFetch::ExtensionFetch( 160 ExtensionDownloader::ExtensionFetch::ExtensionFetch(
172 const std::string& id, 161 const std::string& id,
173 const GURL& url, 162 const GURL& url,
174 const std::string& package_hash, 163 const std::string& package_hash,
175 const std::string& version, 164 const std::string& version,
176 const std::set<int>& request_ids) 165 const std::set<int>& request_ids)
177 : id(id), url(url), package_hash(package_hash), version(version), 166 : id(id),
178 request_ids(request_ids), is_protected(false) {} 167 url(url),
168 package_hash(package_hash),
169 version(version),
170 request_ids(request_ids),
171 credentials(CREDENTIALS_NONE),
172 oauth2_attempt_count(0) {
173 }
179 174
180 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {} 175 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {}
181 176
182 ExtensionDownloader::ExtensionDownloader( 177 ExtensionDownloader::ExtensionDownloader(
183 ExtensionDownloaderDelegate* delegate, 178 ExtensionDownloaderDelegate* delegate,
184 net::URLRequestContextGetter* request_context) 179 net::URLRequestContextGetter* request_context,
185 : delegate_(delegate), 180 IdentityProvider* webstore_identity_provider)
181 : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
182 delegate_(delegate),
186 request_context_(request_context), 183 request_context_(request_context),
187 weak_ptr_factory_(this), 184 weak_ptr_factory_(this),
188 manifests_queue_(&kDefaultBackoffPolicy, 185 manifests_queue_(&kDefaultBackoffPolicy,
189 base::Bind(&ExtensionDownloader::CreateManifestFetcher, 186 base::Bind(&ExtensionDownloader::CreateManifestFetcher,
190 base::Unretained(this))), 187 base::Unretained(this))),
191 extensions_queue_(&kDefaultBackoffPolicy, 188 extensions_queue_(&kDefaultBackoffPolicy,
192 base::Bind(&ExtensionDownloader::CreateExtensionFetcher, 189 base::Bind(&ExtensionDownloader::CreateExtensionFetcher,
193 base::Unretained(this))), 190 base::Unretained(this))),
194 extension_cache_(NULL) { 191 extension_cache_(NULL),
192 identity_provider_(webstore_identity_provider) {
195 DCHECK(delegate_); 193 DCHECK(delegate_);
196 DCHECK(request_context_); 194 DCHECK(request_context_);
197 } 195 }
198 196
199 ExtensionDownloader::~ExtensionDownloader() {} 197 ExtensionDownloader::~ExtensionDownloader() {}
200 198
201 bool ExtensionDownloader::AddExtension(const Extension& extension, 199 bool ExtensionDownloader::AddExtension(const Extension& extension,
202 int request_id) { 200 int request_id) {
203 // Skip extensions with empty update URLs converted from user 201 // Skip extensions with empty update URLs converted from user
204 // scripts. 202 // scripts.
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 if (extension_urls::IsWebstoreUpdateUrl(update_url) && 297 if (extension_urls::IsWebstoreUpdateUrl(update_url) &&
300 !update_url.SchemeIsSecure()) 298 !update_url.SchemeIsSecure())
301 update_url = extension_urls::GetWebstoreUpdateUrl(); 299 update_url = extension_urls::GetWebstoreUpdateUrl();
302 300
303 // Skip extensions with empty IDs. 301 // Skip extensions with empty IDs.
304 if (id.empty()) { 302 if (id.empty()) {
305 LOG(WARNING) << "Found extension with empty ID"; 303 LOG(WARNING) << "Found extension with empty ID";
306 return false; 304 return false;
307 } 305 }
308 306
309 if (update_url.DomainIs("google.com")) { 307 if (update_url.DomainIs(kGoogleDotCom)) {
310 url_stats_.google_url_count++; 308 url_stats_.google_url_count++;
311 } else if (update_url.is_empty()) { 309 } else if (update_url.is_empty()) {
312 url_stats_.no_url_count++; 310 url_stats_.no_url_count++;
313 // Fill in default update URL. 311 // Fill in default update URL.
314 update_url = extension_urls::GetWebstoreUpdateUrl(); 312 update_url = extension_urls::GetWebstoreUpdateUrl();
315 } else { 313 } else {
316 url_stats_.other_url_count++; 314 url_stats_.other_url_count++;
317 } 315 }
318 316
319 switch (extension_type) { 317 switch (extension_type) {
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 } 571 }
574 } 572 }
575 scoped_ptr<ExtensionFetch> fetch(new ExtensionFetch( 573 scoped_ptr<ExtensionFetch> fetch(new ExtensionFetch(
576 update->extension_id, crx_url, update->package_hash, 574 update->extension_id, crx_url, update->package_hash,
577 update->version, fetch_data.request_ids())); 575 update->version, fetch_data.request_ids()));
578 FetchUpdatedExtension(fetch.Pass()); 576 FetchUpdatedExtension(fetch.Pass());
579 } 577 }
580 578
581 // If the manifest response included a <daystart> element, we want to save 579 // 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. 580 // that value for any extensions which had sent a ping in the request.
583 if (fetch_data.base_url().DomainIs("google.com") && 581 if (fetch_data.base_url().DomainIs(kGoogleDotCom) &&
584 results->daystart_elapsed_seconds >= 0) { 582 results->daystart_elapsed_seconds >= 0) {
585 Time day_start = 583 Time day_start =
586 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); 584 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds);
587 585
588 const std::set<std::string>& extension_ids = fetch_data.extension_ids(); 586 const std::set<std::string>& extension_ids = fetch_data.extension_ids();
589 std::set<std::string>::const_iterator i; 587 std::set<std::string>::const_iterator i;
590 for (i = extension_ids.begin(); i != extension_ids.end(); i++) { 588 for (i = extension_ids.begin(); i != extension_ids.end(); i++) {
591 const std::string& id = *i; 589 const std::string& id = *i;
592 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id]; 590 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id];
593 result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL); 591 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, 713 const base::FilePath& crx_path,
716 bool file_ownership_passed) { 714 bool file_ownership_passed) {
717 delegate_->OnExtensionDownloadFinished(fetch_data->id, crx_path, 715 delegate_->OnExtensionDownloadFinished(fetch_data->id, crx_path,
718 file_ownership_passed, fetch_data->url, fetch_data->version, 716 file_ownership_passed, fetch_data->url, fetch_data->version,
719 ping_results_[fetch_data->id], fetch_data->request_ids); 717 ping_results_[fetch_data->id], fetch_data->request_ids);
720 ping_results_.erase(fetch_data->id); 718 ping_results_.erase(fetch_data->id);
721 } 719 }
722 720
723 void ExtensionDownloader::CreateExtensionFetcher() { 721 void ExtensionDownloader::CreateExtensionFetcher() {
724 const ExtensionFetch* fetch = extensions_queue_.active_request(); 722 const ExtensionFetch* fetch = extensions_queue_.active_request();
723 extension_fetcher_.reset(net::URLFetcher::Create(
724 kExtensionFetcherId, fetch->url, net::URLFetcher::GET, this));
725 extension_fetcher_->SetRequestContext(request_context_);
726 extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
727
725 int load_flags = net::LOAD_DISABLE_CACHE; 728 int load_flags = net::LOAD_DISABLE_CACHE;
726 if (!fetch->is_protected || !fetch->url.SchemeIs("https")) { 729 bool is_secure = fetch->url.SchemeIsSecure();
730 if (fetch->credentials != ExtensionFetch::CREDENTIALS_COOKIES || !is_secure) {
727 load_flags |= net::LOAD_DO_NOT_SEND_COOKIES | 731 load_flags |= net::LOAD_DO_NOT_SEND_COOKIES |
728 net::LOAD_DO_NOT_SAVE_COOKIES; 732 net::LOAD_DO_NOT_SAVE_COOKIES;
729 } 733 }
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); 734 extension_fetcher_->SetLoadFlags(load_flags);
734 extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); 735
735 // Download CRX files to a temp file. The blacklist is small and will be 736 // 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. 737 // processed in memory, so it is fetched into a string.
737 if (fetch->id != kBlacklistAppID) { 738 if (fetch->id != kBlacklistAppID) {
738 extension_fetcher_->SaveResponseToTemporaryFile( 739 extension_fetcher_->SaveResponseToTemporaryFile(
739 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); 740 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
740 } 741 }
741 742
743 if (fetch->credentials == ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN &&
744 is_secure) {
745 if (access_token_.empty()) {
746 // We should try OAuth2, but we have no token cached. This
747 // ExtensionFetcher will be started once the token fetch is complete,
748 // in either OnTokenFetchSuccess or OnTokenFetchFailure.
749 DCHECK(identity_provider_);
750 OAuth2TokenService::ScopeSet webstore_scopes;
751 webstore_scopes.insert(kWebstoreOAuth2Scope);
752 access_token_request_ =
753 identity_provider_->GetTokenService()->StartRequest(
754 identity_provider_->GetActiveAccountId(),
755 webstore_scopes,
756 this);
757 return;
758 }
759 extension_fetcher_->AddExtraRequestHeader(
760 base::StringPrintf("%s: Bearer %s",
761 net::HttpRequestHeaders::kAuthorization,
762 access_token_.c_str()));
763 }
764
742 VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id; 765 VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id;
743
744 extension_fetcher_->Start(); 766 extension_fetcher_->Start();
745 } 767 }
746 768
747 void ExtensionDownloader::OnCRXFetchComplete( 769 void ExtensionDownloader::OnCRXFetchComplete(
748 const net::URLFetcher* source, 770 const net::URLFetcher* source,
749 const GURL& url, 771 const GURL& url,
750 const net::URLRequestStatus& status, 772 const net::URLRequestStatus& status,
751 int response_code, 773 int response_code,
752 const base::TimeDelta& backoff_delay) { 774 const base::TimeDelta& backoff_delay) {
753 const std::string& id = extensions_queue_.active_request()->id; 775 ExtensionFetch& active_request = *extensions_queue_.active_request();
776 const std::string& id = active_request.id;
754 if (status.status() == net::URLRequestStatus::SUCCESS && 777 if (status.status() == net::URLRequestStatus::SUCCESS &&
755 (response_code == 200 || url.SchemeIsFile())) { 778 (response_code == 200 || url.SchemeIsFile())) {
756 RETRY_HISTOGRAM("CrxFetchSuccess", 779 RETRY_HISTOGRAM("CrxFetchSuccess",
757 extensions_queue_.active_request_failure_count(), url); 780 extensions_queue_.active_request_failure_count(), url);
758 base::FilePath crx_path; 781 base::FilePath crx_path;
759 // Take ownership of the file at |crx_path|. 782 // Take ownership of the file at |crx_path|.
760 CHECK(source->GetResponseAsFilePath(true, &crx_path)); 783 CHECK(source->GetResponseAsFilePath(true, &crx_path));
761 scoped_ptr<ExtensionFetch> fetch_data = 784 scoped_ptr<ExtensionFetch> fetch_data =
762 extensions_queue_.reset_active_request(); 785 extensions_queue_.reset_active_request();
763 if (extension_cache_) { 786 if (extension_cache_) {
764 const std::string& version = fetch_data->version; 787 const std::string& version = fetch_data->version;
765 extension_cache_->PutExtension(id, crx_path, version, 788 extension_cache_->PutExtension(id, crx_path, version,
766 base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished, 789 base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished,
767 weak_ptr_factory_.GetWeakPtr(), 790 weak_ptr_factory_.GetWeakPtr(),
768 base::Passed(&fetch_data))); 791 base::Passed(&fetch_data)));
769 } else { 792 } else {
770 NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, true); 793 NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, true);
771 } 794 }
772 } else if (ShouldRetryRequestWithCookies( 795 } else if (IterateFetchCredentialsAfterFailure(
773 status, 796 &active_request,
774 response_code, 797 status,
775 extensions_queue_.active_request()->is_protected)) { 798 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); 799 extensions_queue_.RetryRequest(backoff_delay);
785 } else { 800 } else {
786 const std::set<int>& request_ids = 801 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]; 802 const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id];
789 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() 803 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
790 << "' response code:" << response_code; 804 << "' response code:" << response_code;
791 if (ShouldRetryRequest(status, response_code) && 805 if (ShouldRetryRequest(status, response_code) &&
792 extensions_queue_.active_request_failure_count() < kMaxRetries) { 806 extensions_queue_.active_request_failure_count() < kMaxRetries) {
793 extensions_queue_.RetryRequest(backoff_delay); 807 extensions_queue_.RetryRequest(backoff_delay);
794 } else { 808 } else {
795 RETRY_HISTOGRAM("CrxFetchFailure", 809 RETRY_HISTOGRAM("CrxFetchFailure",
796 extensions_queue_.active_request_failure_count(), url); 810 extensions_queue_.active_request_failure_count(), url);
797 // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h) 811 // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h)
(...skipping 25 matching lines...) Expand all
823 837
824 void ExtensionDownloader::NotifyUpdateFound(const std::string& id, 838 void ExtensionDownloader::NotifyUpdateFound(const std::string& id,
825 const std::string& version) { 839 const std::string& version) {
826 UpdateDetails updateInfo(id, Version(version)); 840 UpdateDetails updateInfo(id, Version(version));
827 content::NotificationService::current()->Notify( 841 content::NotificationService::current()->Notify(
828 extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND, 842 extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND,
829 content::NotificationService::AllBrowserContextsAndSources(), 843 content::NotificationService::AllBrowserContextsAndSources(),
830 content::Details<UpdateDetails>(&updateInfo)); 844 content::Details<UpdateDetails>(&updateInfo));
831 } 845 }
832 846
847 bool ExtensionDownloader::IterateFetchCredentialsAfterFailure(
848 ExtensionFetch* fetch,
849 const net::URLRequestStatus& status,
850 int response_code) {
851 bool auth_failure = status.status() == net::URLRequestStatus::CANCELED ||
852 (status.status() == net::URLRequestStatus::SUCCESS &&
853 (response_code == net::HTTP_UNAUTHORIZED ||
854 response_code == net::HTTP_FORBIDDEN));
855 if (!auth_failure) {
856 return false;
857 }
858 // Here we decide what to do next if the server refused to authorize this
859 // fetch.
860 switch (fetch->credentials) {
861 case ExtensionFetch::CREDENTIALS_NONE:
862 if (fetch->url.DomainIs(kGoogleDotCom) && identity_provider_) {
863 fetch->credentials = ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN;
864 } else {
865 fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
866 }
867 return true;
868 case ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN:
869 fetch->oauth2_attempt_count++;
870 // OAuth2 may fail due to an expired access token, in which case we
871 // should invalidate the token and try again.
872 if (response_code == net::HTTP_UNAUTHORIZED &&
873 fetch->oauth2_attempt_count <= kMaxOAuth2Attempts) {
874 DCHECK(identity_provider_ != NULL);
875 OAuth2TokenService::ScopeSet webstore_scopes;
876 webstore_scopes.insert(kWebstoreOAuth2Scope);
877 identity_provider_->GetTokenService()->InvalidateToken(
878 identity_provider_->GetActiveAccountId(),
879 webstore_scopes,
880 access_token_);
881 access_token_.clear();
882 return true;
883 }
884 // Either there is no Gaia identity available, the active identity
885 // doesn't have access to this resource, or the server keeps returning
886 // 401s and we've retried too many times. Fall back on cookies.
887 if (access_token_.empty() ||
888 response_code == net::HTTP_FORBIDDEN ||
889 fetch->oauth2_attempt_count > kMaxOAuth2Attempts) {
890 fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
891 return true;
892 }
893 // Something else is wrong. Time to give up.
894 return false;
895 case ExtensionFetch::CREDENTIALS_COOKIES:
896 if (response_code == net::HTTP_FORBIDDEN) {
897 // Try the next session identity, up to some maximum.
898 return IncrementAuthUserIndex(&fetch->url);
899 }
900 return false;
901 default:
902 NOTREACHED();
903 }
904 NOTREACHED();
905 return false;
906 }
907
908 void ExtensionDownloader::OnGetTokenSuccess(
909 const OAuth2TokenService::Request* request,
910 const std::string& access_token,
911 const base::Time& expiration_time) {
912 access_token_ = access_token;
913 extension_fetcher_->AddExtraRequestHeader(
914 base::StringPrintf("%s: Bearer %s",
915 net::HttpRequestHeaders::kAuthorization,
916 access_token_.c_str()));
917 extension_fetcher_->Start();
918 }
919
920 void ExtensionDownloader::OnGetTokenFailure(
921 const OAuth2TokenService::Request* request,
922 const GoogleServiceAuthError& error) {
923 // If we fail to get an access token, kick the pending fetch and let it fall
924 // back on cookies.
925 extension_fetcher_->Start();
926 }
927
833 } // namespace extensions 928 } // 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