Index: chrome/browser/chrome_to_mobile_service.cc |
diff --git a/chrome/browser/chrome_to_mobile_service.cc b/chrome/browser/chrome_to_mobile_service.cc |
index b8cd66baea6e842840e2d76f993eb90f77341549..7cd802033a7a8537bc5248db334c54b710b2d4f6 100644 |
--- a/chrome/browser/chrome_to_mobile_service.cc |
+++ b/chrome/browser/chrome_to_mobile_service.cc |
@@ -42,6 +42,7 @@ |
#include "google/cacheinvalidation/types.pb.h" |
#include "net/base/escape.h" |
#include "net/base/load_flags.h" |
+#include "net/http/http_status_code.h" |
#include "net/url_request/url_fetcher.h" |
#include "net/url_request/url_request_context_getter.h" |
#include "sync/notifier/invalidation_util.h" |
@@ -49,15 +50,10 @@ |
namespace { |
// The maximum number of retries for the URLFetcher requests. |
-const size_t kMaxRetries = 1; |
+const size_t kMaxRetries = 5; |
-// The number of hours to delay before retrying authentication on failure. |
-const size_t kAuthRetryDelayHours = 6; |
- |
-// The number of hours before subsequent search requests are allowed. |
-// This value is used to throttle expensive cloud print search requests. |
-// Note that this limitation does not hold across application restarts. |
-const int kSearchRequestDelayHours = 24; |
+// The number of hours to delay before retrying certain failed operations. |
+const size_t kDelayHours = 1; |
// The sync invalidation object ID for Chrome to Mobile's mobile device list. |
// This corresponds with cloud print's server-side invalidation object ID. |
@@ -322,7 +318,8 @@ void ChromeToMobileService::Observe( |
TokenService::TokenAvailableDetails* token_details = |
content::Details<TokenService::TokenAvailableDetails>(details).ptr(); |
// Invalidate the cloud print access token on Gaia login token updates. |
- if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) |
+ if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken || |
+ token_details->service() == GaiaConstants::kGaiaOAuth2LoginAccessToken) |
access_token_.clear(); |
} |
@@ -346,12 +343,20 @@ void ChromeToMobileService::OnGetTokenSuccess( |
void ChromeToMobileService::OnGetTokenFailure( |
const GoogleServiceAuthError& error) { |
+ LogMetric(BAD_TOKEN); |
+ access_token_.clear(); |
access_token_fetcher_.reset(); |
auth_retry_timer_.Stop(); |
- auth_retry_timer_.Start( |
- FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours), |
- this, &ChromeToMobileService::RequestAccessToken); |
+ base::TimeDelta delay = std::max(base::TimeDelta::FromHours(kDelayHours), |
+ auth_retry_timer_.GetCurrentDelay() * 2); |
+ auth_retry_timer_.Start(FROM_HERE, delay, this, |
+ &ChromeToMobileService::RequestAccessToken); |
+ |
+ // Clear the mobile list, which may be (or become) out of date. |
+ ListValue empty; |
+ profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, empty); |
+ UpdateCommandState(); |
} |
void ChromeToMobileService::OnNotificationsEnabled() { |
@@ -486,10 +491,16 @@ void ChromeToMobileService::RequestAccessToken() { |
registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, |
content::Source<TokenService>(token_service)); |
- // Deny concurrent requests and bail without a valid Gaia login refresh token. |
- if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken()) |
+ // Deny concurrent requests. |
+ if (access_token_fetcher_.get()) |
return; |
+ // Handle invalid login refresh tokens as a failure. |
+ if (!token_service->HasOAuthLoginToken()) { |
+ OnGetTokenFailure(GoogleServiceAuthError(GoogleServiceAuthError::NONE)); |
+ return; |
+ } |
+ |
auth_retry_timer_.Stop(); |
access_token_fetcher_.reset( |
new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext())); |
@@ -501,6 +512,7 @@ void ChromeToMobileService::RequestAccessToken() { |
} |
void ChromeToMobileService::RequestDeviceSearch() { |
+ search_retry_timer_.Stop(); |
if (access_token_.empty()) { |
// Enqueue this task to perform after obtaining an access token. |
task_queue_.push(base::Bind(&ChromeToMobileService::RequestDeviceSearch, |
@@ -522,6 +534,7 @@ void ChromeToMobileService::HandleSearchResponse( |
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
DCHECK_EQ(source->GetURL(), GetSearchURL(cloud_print_url_)); |
+ ListValue mobiles; |
std::string data; |
ListValue* list = NULL; |
DictionaryValue* dictionary = NULL; |
@@ -529,7 +542,6 @@ void ChromeToMobileService::HandleSearchResponse( |
scoped_ptr<Value> json(base::JSONReader::Read(data)); |
if (json.get() && json->GetAsDictionary(&dictionary) && dictionary && |
dictionary->GetList(cloud_print::kPrinterListValue, &list)) { |
- ListValue mobiles; |
std::string type, name, id; |
DictionaryValue* printer = NULL; |
DictionaryValue* mobile = NULL; |
@@ -550,29 +562,49 @@ void ChromeToMobileService::HandleSearchResponse( |
} |
} |
} |
- |
- // Update the cached mobile device list in profile prefs. |
- profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles); |
- |
- if (HasMobiles()) |
- LogMetric(DEVICES_AVAILABLE); |
- UpdateCommandState(); |
+ } else if (source->GetResponseCode() == net::HTTP_FORBIDDEN) { |
+ LogMetric(BAD_SEARCH_AUTH); |
+ // Invalidate the access token and retry a delayed search on access errors. |
+ access_token_.clear(); |
+ search_retry_timer_.Stop(); |
+ base::TimeDelta delay = std::max(base::TimeDelta::FromHours(kDelayHours), |
+ search_retry_timer_.GetCurrentDelay() * 2); |
+ search_retry_timer_.Start(FROM_HERE, delay, this, |
+ &ChromeToMobileService::RequestDeviceSearch); |
+ } else { |
+ LogMetric(BAD_SEARCH_OTHER); |
} |
+ |
+ // Update the cached mobile device list in profile prefs. |
+ profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles); |
+ if (HasMobiles()) |
+ LogMetric(DEVICES_AVAILABLE); |
+ UpdateCommandState(); |
} |
void ChromeToMobileService::HandleSubmitResponse( |
const net::URLFetcher* source) { |
// Get the success value from the cloud print server response data. |
std::string data; |
- source->GetResponseAsString(&data); |
bool success = false; |
+ source->GetResponseAsString(&data); |
DictionaryValue* dictionary = NULL; |
scoped_ptr<Value> json(base::JSONReader::Read(data)); |
- if (json.get() && json->GetAsDictionary(&dictionary) && dictionary) |
+ if (json.get() && json->GetAsDictionary(&dictionary) && dictionary) { |
dictionary->GetBoolean("success", &success); |
+ int error_code = -1; |
+ if (dictionary->GetInteger("errorCode", &error_code)) |
+ LogMetric(error_code == 407 ? BAD_SEND_407 : BAD_SEND_ERROR); |
+ } else if (source->GetResponseCode() == net::HTTP_FORBIDDEN) { |
+ LogMetric(BAD_SEND_AUTH); |
+ } else { |
+ LogMetric(BAD_SEND_OTHER); |
+ } |
// Log each URL and [DELAYED_]SNAPSHOT job submission response. |
LogMetric(success ? SEND_SUCCESS : SEND_ERROR); |
+ LOG_IF(INFO, !success) << "ChromeToMobile send failed (" << |
+ source->GetResponseCode() << "): " << data; |
// Get the observer for this job submission response. |
base::WeakPtr<Observer> observer; |