Index: sync/internal_api/attachments/attachment_uploader_impl.cc |
diff --git a/sync/internal_api/attachments/attachment_uploader_impl.cc b/sync/internal_api/attachments/attachment_uploader_impl.cc |
index 25630dcaba8b2a71f79192b91921497bb17587bd..90c620e5802864cba4629bdfff72ec57cac32596 100644 |
--- a/sync/internal_api/attachments/attachment_uploader_impl.cc |
+++ b/sync/internal_api/attachments/attachment_uploader_impl.cc |
@@ -7,6 +7,7 @@ |
#include "base/bind.h" |
#include "base/message_loop/message_loop.h" |
#include "base/threading/non_thread_safe.h" |
+#include "google_apis/gaia/gaia_constants.h" |
#include "net/base/load_flags.h" |
#include "net/http/http_status_code.h" |
#include "net/url_request/url_fetcher.h" |
@@ -25,18 +26,23 @@ namespace syncer { |
// Encapsulates all the state associated with a single upload. |
class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate, |
+ public OAuth2TokenService::Consumer, |
public base::NonThreadSafe { |
public: |
// Construct an UploadState. |
// |
// |owner| is a pointer to the object that will own (and must outlive!) this |
// |UploadState. |
- UploadState(const GURL& upload_url, |
- const scoped_refptr<net::URLRequestContextGetter>& |
- url_request_context_getter, |
- const Attachment& attachment, |
- const UploadCallback& user_callback, |
- AttachmentUploaderImpl* owner); |
+ UploadState( |
+ const GURL& upload_url, |
+ const scoped_refptr<net::URLRequestContextGetter>& |
+ url_request_context_getter, |
+ const Attachment& attachment, |
+ const UploadCallback& user_callback, |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider, |
+ AttachmentUploaderImpl* owner); |
virtual ~UploadState(); |
@@ -50,17 +56,34 @@ class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate, |
// URLFetcher implementation. |
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; |
+ // OAuth2TokenService::Consumer. |
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, |
+ const std::string& access_token, |
+ const base::Time& expiration_time) OVERRIDE; |
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) OVERRIDE; |
+ |
private: |
typedef std::vector<UploadCallback> UploadCallbackList; |
+ void GetToken(); |
+ |
+ void ReportResult(const UploadResult& result, |
+ const AttachmentId& attachment_id); |
+ |
GURL upload_url_; |
const scoped_refptr<net::URLRequestContextGetter>& |
url_request_context_getter_; |
Attachment attachment_; |
UploadCallbackList user_callbacks_; |
scoped_ptr<net::URLFetcher> fetcher_; |
+ std::string account_id_; |
+ OAuth2TokenService::ScopeSet scopes_; |
+ std::string access_token_; |
+ OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider_; |
// Pointer to the AttachmentUploaderImpl that owns this object. |
AttachmentUploaderImpl* owner_; |
+ scoped_ptr<OAuth2TokenServiceRequest> access_token_request_; |
DISALLOW_COPY_AND_ASSIGN(UploadState); |
}; |
@@ -71,33 +94,26 @@ AttachmentUploaderImpl::UploadState::UploadState( |
url_request_context_getter, |
const Attachment& attachment, |
const UploadCallback& user_callback, |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider, |
AttachmentUploaderImpl* owner) |
- : upload_url_(upload_url), |
+ : OAuth2TokenService::Consumer("attachment-uploader-impl"), |
+ upload_url_(upload_url), |
url_request_context_getter_(url_request_context_getter), |
attachment_(attachment), |
user_callbacks_(1, user_callback), |
+ account_id_(account_id), |
+ scopes_(scopes), |
+ token_service_provider_(token_service_provider), |
owner_(owner) { |
- DCHECK(url_request_context_getter_); |
DCHECK(upload_url_.is_valid()); |
+ DCHECK(url_request_context_getter_); |
+ DCHECK(!account_id_.empty()); |
+ DCHECK(!scopes_.empty()); |
+ DCHECK(token_service_provider_); |
DCHECK(owner_); |
- fetcher_.reset( |
- net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this)); |
- fetcher_->SetRequestContext(url_request_context_getter_.get()); |
- // TODO(maniscalco): Is there a better way? Copying the attachment data into |
- // a string feels wrong given how large attachments may be (several MBs). If |
- // we may end up switching from URLFetcher to URLRequest, this copy won't be |
- // necessary. |
- scoped_refptr<base::RefCountedMemory> memory = attachment.GetData(); |
- const std::string upload_content(memory->front_as<char>(), memory->size()); |
- fetcher_->SetUploadData(kContentType, upload_content); |
- // TODO(maniscalco): Add authentication support (bug 371516). |
- fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
- net::LOAD_DO_NOT_SEND_COOKIES | |
- net::LOAD_DISABLE_CACHE); |
- // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and |
- // Content-length) on the request and include the content's MD5, |
- // AttachmentId's unique_id and the "sync birthday" (bug 371521). |
- fetcher_->Start(); |
+ GetToken(); |
} |
AttachmentUploaderImpl::UploadState::~UploadState() { |
@@ -117,20 +133,75 @@ const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() { |
void AttachmentUploaderImpl::UploadState::OnURLFetchComplete( |
const net::URLFetcher* source) { |
DCHECK(CalledOnValidThread()); |
- // TODO(maniscalco): Once the protocol is better defined, deal with the |
- // various HTTP response code we may encounter. |
UploadResult result = UPLOAD_UNSPECIFIED_ERROR; |
+ AttachmentId attachment_id = attachment_.GetId(); |
if (source->GetResponseCode() == net::HTTP_OK) { |
result = UPLOAD_SUCCESS; |
+ // TODO(maniscalco): Update the attachment id with server address |
+ // information before passing it to the callback (bug 371522). |
+ } else if (source->GetResponseCode() == net::HTTP_UNAUTHORIZED) { |
+ // TODO(maniscalco): One possibility is that we received a 401 because our |
+ // access token has expired. We should probably fetch a new access token |
+ // and retry this upload before giving up and reporting failure to our |
+ // caller (bug 380437). |
+ OAuth2TokenServiceRequest::InvalidateToken( |
+ token_service_provider_, account_id_, scopes_, access_token_); |
+ } else { |
+ // TODO(maniscalco): Once the protocol is better defined, deal with the |
+ // various HTTP response codes we may encounter. |
} |
- // TODO(maniscalco): Update the attachment id with server address information |
- // before passing it to the callback (bug 371522). |
- AttachmentId updated_id = attachment_.GetId(); |
+ ReportResult(result, attachment_id); |
+} |
+ |
+void AttachmentUploaderImpl::UploadState::OnGetTokenSuccess( |
+ const OAuth2TokenService::Request* request, |
+ const std::string& access_token, |
+ const base::Time& expiration_time) { |
+ DCHECK_EQ(access_token_request_.get(), request); |
+ access_token_request_.reset(); |
+ access_token_ = access_token; |
+ fetcher_.reset( |
+ net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this)); |
+ fetcher_->SetRequestContext(url_request_context_getter_.get()); |
+ // TODO(maniscalco): Is there a better way? Copying the attachment data into |
+ // a string feels wrong given how large attachments may be (several MBs). If |
+ // we may end up switching from URLFetcher to URLRequest, this copy won't be |
+ // necessary. |
+ scoped_refptr<base::RefCountedMemory> memory = attachment_.GetData(); |
+ const std::string upload_content(memory->front_as<char>(), memory->size()); |
+ fetcher_->SetUploadData(kContentType, upload_content); |
+ const std::string auth_header("Authorization: Bearer " + access_token_); |
+ fetcher_->AddExtraRequestHeader(auth_header); |
+ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
+ net::LOAD_DO_NOT_SEND_COOKIES | |
+ net::LOAD_DISABLE_CACHE); |
+ // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and |
+ // Content-length) on the request and include the content's MD5, |
+ // AttachmentId's unique_id and the "sync birthday" (bug 371521). |
+ fetcher_->Start(); |
+} |
+ |
+void AttachmentUploaderImpl::UploadState::OnGetTokenFailure( |
+ const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) { |
+ DCHECK_EQ(access_token_request_.get(), request); |
+ access_token_request_.reset(); |
+ ReportResult(UPLOAD_UNSPECIFIED_ERROR, attachment_.GetId()); |
+} |
+ |
+void AttachmentUploaderImpl::UploadState::GetToken() { |
+ access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart( |
+ token_service_provider_, account_id_, scopes_, this); |
+} |
+ |
+void AttachmentUploaderImpl::UploadState::ReportResult( |
+ const UploadResult& result, |
+ const AttachmentId& attachment_id) { |
UploadCallbackList::const_iterator iter = user_callbacks_.begin(); |
UploadCallbackList::const_iterator end = user_callbacks_.end(); |
for (; iter != end; ++iter) { |
base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(*iter, result, updated_id)); |
+ FROM_HERE, base::Bind(*iter, result, attachment_id)); |
} |
// Destroy this object and return immediately. |
owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id()); |
@@ -140,10 +211,18 @@ void AttachmentUploaderImpl::UploadState::OnURLFetchComplete( |
AttachmentUploaderImpl::AttachmentUploaderImpl( |
const std::string& url_prefix, |
const scoped_refptr<net::URLRequestContextGetter>& |
- url_request_context_getter) |
+ url_request_context_getter, |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ scoped_ptr<OAuth2TokenServiceRequest::TokenServiceProvider> |
+ token_service_provider) |
: url_prefix_(url_prefix), |
- url_request_context_getter_(url_request_context_getter) { |
+ url_request_context_getter_(url_request_context_getter), |
+ account_id_(account_id), |
+ scopes_(scopes), |
+ token_service_provider_(token_service_provider.Pass()) { |
DCHECK(CalledOnValidThread()); |
+ DCHECK(token_service_provider_); |
} |
AttachmentUploaderImpl::~AttachmentUploaderImpl() { |
@@ -159,8 +238,15 @@ void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment, |
StateMap::iterator iter = state_map_.find(unique_id); |
if (iter == state_map_.end()) { |
const GURL url = GetUploadURLForAttachmentId(attachment_id); |
- scoped_ptr<UploadState> upload_state(new UploadState( |
- url, url_request_context_getter_, attachment, callback, this)); |
+ scoped_ptr<UploadState> upload_state( |
+ new UploadState(url, |
+ url_request_context_getter_, |
+ attachment, |
+ callback, |
+ account_id_, |
+ scopes_, |
+ token_service_provider_.get(), |
+ this)); |
state_map_.add(unique_id, upload_state.Pass()); |
} else { |
DCHECK( |