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

Unified Diff: chrome/browser/chromeos/policy/upload_job_impl.cc

Issue 1875443003: Retry uploading in UploadJobImpl when error occurs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix include Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/policy/upload_job_impl.cc
diff --git a/chrome/browser/chromeos/policy/upload_job_impl.cc b/chrome/browser/chromeos/policy/upload_job_impl.cc
index d557c287b505fc11be6cbe0f215af769a4bd996e..c8a02e74dcd16eb1e90d5c41e8ffb73e17827c11 100644
--- a/chrome/browser/chromeos/policy/upload_job_impl.cc
+++ b/chrome/browser/chromeos/policy/upload_job_impl.cc
@@ -8,6 +8,7 @@
#include <set>
#include <utility>
+#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@@ -28,12 +29,15 @@ const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
// Value the "Content-Type" field will be set to in the POST request.
const char kUploadContentType[] = "multipart/form-data";
-// Number of upload retries.
-const int kMaxRetries = 1;
+// Number of upload attempts.
+const int kMaxAttempts = 4;
// Max size of MIME boundary according to RFC 1341, section 7.2.1.
const size_t kMaxMimeBoundarySize = 70;
+// Delay after each unsuccessful upload attempt.
+long g_retry_delay_ms = 25000;
+
} // namespace
UploadJobImpl::Delegate::~Delegate() {
@@ -127,7 +131,8 @@ UploadJobImpl::UploadJobImpl(
OAuth2TokenService* token_service,
scoped_refptr<net::URLRequestContextGetter> url_context_getter,
Delegate* delegate,
- std::unique_ptr<MimeBoundaryGenerator> boundary_generator)
+ std::unique_ptr<MimeBoundaryGenerator> boundary_generator,
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
: OAuth2TokenService::Consumer("cros_upload_job"),
upload_url_(upload_url),
account_id_(account_id),
@@ -136,7 +141,9 @@ UploadJobImpl::UploadJobImpl(
delegate_(delegate),
boundary_generator_(std::move(boundary_generator)),
state_(IDLE),
- retry_(0) {
+ retry_(0),
+ task_runner_(task_runner),
+ weak_factory_(this) {
DCHECK(token_service_);
DCHECK(url_context_getter_);
DCHECK(delegate_);
@@ -154,6 +161,7 @@ void UploadJobImpl::AddDataSegment(
const std::string& filename,
const std::map<std::string, std::string>& header_entries,
std::unique_ptr<std::string> data) {
+ DCHECK(thread_checker_.CalledOnValidThread());
// Cannot add data to busy or failed instance.
DCHECK_EQ(IDLE, state_);
if (state_ != IDLE)
@@ -165,14 +173,26 @@ void UploadJobImpl::AddDataSegment(
}
void UploadJobImpl::Start() {
+ DCHECK(thread_checker_.CalledOnValidThread());
// Cannot start an upload on a busy or failed instance.
DCHECK_EQ(IDLE, state_);
if (state_ != IDLE)
return;
+ DCHECK_EQ(0, retry_);
+
RequestAccessToken();
}
+// static
+void UploadJobImpl::SetRetryDelayForTesting(long retry_delay_ms) {
+ CHECK_GE(retry_delay_ms, 0);
+ g_retry_delay_ms = retry_delay_ms;
+}
+
void UploadJobImpl::RequestAccessToken() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!access_token_request_);
+
state_ = ACQUIRING_TOKEN;
OAuth2TokenService::ScopeSet scope_set;
@@ -264,13 +284,15 @@ void UploadJobImpl::CreateAndStartURLFetcher(const std::string& access_token) {
upload_fetcher_->Start();
}
-void UploadJobImpl::StartUpload(const std::string& access_token) {
+void UploadJobImpl::StartUpload() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
if (!SetUpMultipart()) {
LOG(ERROR) << "Multipart message assembly failed.";
state_ = ERROR;
return;
}
- CreateAndStartURLFetcher(access_token);
+ CreateAndStartURLFetcher(access_token_);
state_ = UPLOADING;
}
@@ -284,7 +306,7 @@ void UploadJobImpl::OnGetTokenSuccess(
// Also cache the token locally, so that we can revoke it later if necessary.
access_token_ = access_token;
- StartUpload(access_token);
+ StartUpload();
}
void UploadJobImpl::OnGetTokenFailure(
@@ -294,57 +316,71 @@ void UploadJobImpl::OnGetTokenFailure(
DCHECK_EQ(access_token_request_.get(), request);
access_token_request_.reset();
LOG(ERROR) << "Token request failed: " << error.ToString();
- state_ = ERROR;
- delegate_->OnFailure(AUTHENTICATION_ERROR);
+ HandleError(AUTHENTICATION_ERROR);
+}
+
+void UploadJobImpl::HandleError(ErrorCode error_code) {
+ retry_++;
+ upload_fetcher_.reset();
+
+ LOG(ERROR) << "Upload failed, error code: " << error_code;
+
+ if (retry_ >= kMaxAttempts) {
+ // Maximum number of attempts reached, failure.
+ LOG(ERROR) << "Maximum number of attempts reached.";
+ access_token_.clear();
+ post_data_.reset();
+ state_ = ERROR;
+ delegate_->OnFailure(error_code);
+ } else {
+ if (error_code == AUTHENTICATION_ERROR) {
+ LOG(ERROR) << "Retrying upload with a new token.";
+ // Request new token and retry.
+ OAuth2TokenService::ScopeSet scope_set;
+ scope_set.insert(GaiaConstants::kDeviceManagementServiceOAuth);
+ token_service_->InvalidateAccessToken(account_id_, scope_set,
+ access_token_);
+ access_token_.clear();
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&UploadJobImpl::RequestAccessToken,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(g_retry_delay_ms));
+ } else {
+ // Retry without a new token.
+ state_ = ACQUIRING_TOKEN;
+ LOG(WARNING) << "Retrying upload with the same token.";
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&UploadJobImpl::StartUpload, weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(g_retry_delay_ms));
+ }
+ }
}
void UploadJobImpl::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK_EQ(upload_fetcher_.get(), source);
+ DCHECK_EQ(UPLOADING, state_);
const net::URLRequestStatus& status = source->GetStatus();
if (!status.is_success()) {
LOG(ERROR) << "URLRequestStatus error " << status.error();
- upload_fetcher_.reset();
- state_ = ERROR;
- post_data_.reset();
- delegate_->OnFailure(NETWORK_ERROR);
- return;
- }
-
- const int response_code = source->GetResponseCode();
- const bool success = response_code == net::HTTP_OK;
- if (!success)
- LOG(ERROR) << "POST request failed with HTTP status code " << response_code;
-
- if (response_code == net::HTTP_UNAUTHORIZED) {
- if (retry_ >= kMaxRetries) {
+ HandleError(NETWORK_ERROR);
+ } else {
+ const int response_code = source->GetResponseCode();
+ if (response_code == net::HTTP_OK) {
+ // Successful upload
upload_fetcher_.reset();
- LOG(ERROR) << "Unauthorized request.";
- state_ = ERROR;
+ access_token_.clear();
post_data_.reset();
- delegate_->OnFailure(AUTHENTICATION_ERROR);
- return;
+ state_ = SUCCESS;
+ delegate_->OnSuccess();
+ } else if (response_code == net::HTTP_UNAUTHORIZED) {
+ LOG(ERROR) << "Unauthorized request.";
+ HandleError(AUTHENTICATION_ERROR);
+ } else {
+ LOG(ERROR) << "POST request failed with HTTP status code "
+ << response_code << ".";
+ HandleError(SERVER_ERROR);
}
- retry_++;
- upload_fetcher_.reset();
- OAuth2TokenService::ScopeSet scope_set;
- scope_set.insert(GaiaConstants::kDeviceManagementServiceOAuth);
- token_service_->InvalidateAccessToken(account_id_, scope_set,
- access_token_);
- access_token_.clear();
- RequestAccessToken();
- return;
- }
-
- upload_fetcher_.reset();
- access_token_.clear();
- upload_fetcher_.reset();
- post_data_.reset();
- if (success) {
- state_ = SUCCESS;
- delegate_->OnSuccess();
- } else {
- state_ = ERROR;
- delegate_->OnFailure(SERVER_ERROR);
}
}
« no previous file with comments | « chrome/browser/chromeos/policy/upload_job_impl.h ('k') | chrome/browser/chromeos/policy/upload_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698