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

Side by Side Diff: sync/internal_api/attachments/attachment_uploader_impl.cc

Issue 304253010: Add authentication support to AttachmentUploaderImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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
« no previous file with comments | « no previous file | sync/internal_api/attachments/attachment_uploader_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "sync/internal_api/public/attachments/attachment_uploader_impl.h" 5 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop.h"
9 #include "base/threading/non_thread_safe.h" 9 #include "base/threading/non_thread_safe.h"
10 #include "google_apis/gaia/gaia_constants.h"
10 #include "net/base/load_flags.h" 11 #include "net/base/load_flags.h"
11 #include "net/http/http_status_code.h" 12 #include "net/http/http_status_code.h"
12 #include "net/url_request/url_fetcher.h" 13 #include "net/url_request/url_fetcher.h"
13 #include "net/url_request/url_fetcher_delegate.h" 14 #include "net/url_request/url_fetcher_delegate.h"
14 #include "sync/api/attachments/attachment.h" 15 #include "sync/api/attachments/attachment.h"
15 #include "sync/protocol/sync.pb.h" 16 #include "sync/protocol/sync.pb.h"
16 #include "url/gurl.h" 17 #include "url/gurl.h"
17 18
18 namespace { 19 namespace {
19 20
20 const char kContentType[] = "application/octet-stream"; 21 const char kContentType[] = "application/octet-stream";
21 22
22 } // namespace 23 } // namespace
23 24
24 namespace syncer { 25 namespace syncer {
25 26
26 // Encapsulates all the state associated with a single upload. 27 // Encapsulates all the state associated with a single upload.
27 class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate, 28 class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
29 public OAuth2TokenService::Consumer,
28 public base::NonThreadSafe { 30 public base::NonThreadSafe {
29 public: 31 public:
30 // Construct an UploadState. 32 // Construct an UploadState.
31 // 33 //
32 // |owner| is a pointer to the object that will own (and must outlive!) this 34 // |owner| is a pointer to the object that will own (and must outlive!) this
33 // |UploadState. 35 // |UploadState.
34 UploadState(const GURL& upload_url, 36 UploadState(
35 const scoped_refptr<net::URLRequestContextGetter>& 37 const GURL& upload_url,
36 url_request_context_getter, 38 const scoped_refptr<net::URLRequestContextGetter>&
37 const Attachment& attachment, 39 url_request_context_getter,
38 const UploadCallback& user_callback, 40 const Attachment& attachment,
39 AttachmentUploaderImpl* owner); 41 const UploadCallback& user_callback,
42 const std::string& account_id,
43 OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider,
44 AttachmentUploaderImpl* owner);
40 45
41 virtual ~UploadState(); 46 virtual ~UploadState();
42 47
43 // Add |user_callback| to the list of callbacks to be invoked when this upload 48 // Add |user_callback| to the list of callbacks to be invoked when this upload
44 // completed. 49 // completed.
45 void AddUserCallback(const UploadCallback& user_callback); 50 void AddUserCallback(const UploadCallback& user_callback);
46 51
47 // Return the Attachment this object is uploading. 52 // Return the Attachment this object is uploading.
48 const Attachment& GetAttachment(); 53 const Attachment& GetAttachment();
49 54
50 // URLFetcher implementation. 55 // URLFetcher implementation.
51 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 56 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
52 57
58 // OAuth2TokenService::Consumer.
59 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
60 const std::string& access_token,
61 const base::Time& expiration_time) OVERRIDE;
62 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
63 const GoogleServiceAuthError& error) OVERRIDE;
64
53 private: 65 private:
54 typedef std::vector<UploadCallback> UploadCallbackList; 66 typedef std::vector<UploadCallback> UploadCallbackList;
55 67
68 void GetToken();
69
70 void ReportResult(const UploadResult& result,
71 const AttachmentId& attachment_id);
72
56 GURL upload_url_; 73 GURL upload_url_;
57 const scoped_refptr<net::URLRequestContextGetter>& 74 const scoped_refptr<net::URLRequestContextGetter>&
58 url_request_context_getter_; 75 url_request_context_getter_;
59 Attachment attachment_; 76 Attachment attachment_;
60 UploadCallbackList user_callbacks_; 77 UploadCallbackList user_callbacks_;
61 scoped_ptr<net::URLFetcher> fetcher_; 78 scoped_ptr<net::URLFetcher> fetcher_;
79 std::string account_id_;
80 std::string access_token_;
81 OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider_;
62 // Pointer to the AttachmentUploaderImpl that owns this object. 82 // Pointer to the AttachmentUploaderImpl that owns this object.
83 OAuth2TokenService::ScopeSet scopes_;
63 AttachmentUploaderImpl* owner_; 84 AttachmentUploaderImpl* owner_;
85 scoped_ptr<OAuth2TokenServiceRequest> access_token_request_;
86
87 // Must be last data member.
88 base::WeakPtrFactory<UploadState> weak_ptr_factory_;
pavely 2014/06/03 17:38:54 Why do you need weak_ptr_factory?
maniscalco 2014/06/04 00:20:50 Good catch. Removed. It was left over from a pre
64 89
65 DISALLOW_COPY_AND_ASSIGN(UploadState); 90 DISALLOW_COPY_AND_ASSIGN(UploadState);
66 }; 91 };
67 92
68 AttachmentUploaderImpl::UploadState::UploadState( 93 AttachmentUploaderImpl::UploadState::UploadState(
69 const GURL& upload_url, 94 const GURL& upload_url,
70 const scoped_refptr<net::URLRequestContextGetter>& 95 const scoped_refptr<net::URLRequestContextGetter>&
71 url_request_context_getter, 96 url_request_context_getter,
72 const Attachment& attachment, 97 const Attachment& attachment,
73 const UploadCallback& user_callback, 98 const UploadCallback& user_callback,
99 const std::string& account_id,
100 OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider,
74 AttachmentUploaderImpl* owner) 101 AttachmentUploaderImpl* owner)
75 : upload_url_(upload_url), 102 : OAuth2TokenService::Consumer("attachment-uploader-impl"),
103 upload_url_(upload_url),
76 url_request_context_getter_(url_request_context_getter), 104 url_request_context_getter_(url_request_context_getter),
77 attachment_(attachment), 105 attachment_(attachment),
78 user_callbacks_(1, user_callback), 106 user_callbacks_(1, user_callback),
79 owner_(owner) { 107 account_id_(account_id),
108 token_service_provider_(token_service_provider),
109 owner_(owner),
110 weak_ptr_factory_(this) {
111 DCHECK(upload_url_.is_valid());
80 DCHECK(url_request_context_getter_); 112 DCHECK(url_request_context_getter_);
81 DCHECK(upload_url_.is_valid()); 113 DCHECK(!account_id_.empty());
114 DCHECK(token_service_provider_);
82 DCHECK(owner_); 115 DCHECK(owner_);
83 fetcher_.reset( 116 scopes_.insert(GaiaConstants::kChromeSyncOAuth2Scope);
pavely 2014/06/03 17:38:54 If this is managed user then scope should be diffe
maniscalco 2014/06/04 00:20:50 Good point. Done. The scope set is now part of A
84 net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this)); 117 GetToken();
85 fetcher_->SetRequestContext(url_request_context_getter_.get());
86 // TODO(maniscalco): Is there a better way? Copying the attachment data into
87 // a string feels wrong given how large attachments may be (several MBs). If
88 // we may end up switching from URLFetcher to URLRequest, this copy won't be
89 // necessary.
90 scoped_refptr<base::RefCountedMemory> memory = attachment.GetData();
91 const std::string upload_content(memory->front_as<char>(), memory->size());
92 fetcher_->SetUploadData(kContentType, upload_content);
93 // TODO(maniscalco): Add authentication support (bug 371516).
94 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
95 net::LOAD_DO_NOT_SEND_COOKIES |
96 net::LOAD_DISABLE_CACHE);
97 // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and
98 // Content-length) on the request and include the content's MD5,
99 // AttachmentId's unique_id and the "sync birthday" (bug 371521).
100 fetcher_->Start();
101 } 118 }
102 119
103 AttachmentUploaderImpl::UploadState::~UploadState() { 120 AttachmentUploaderImpl::UploadState::~UploadState() {
104 } 121 }
105 122
106 void AttachmentUploaderImpl::UploadState::AddUserCallback( 123 void AttachmentUploaderImpl::UploadState::AddUserCallback(
107 const UploadCallback& user_callback) { 124 const UploadCallback& user_callback) {
108 DCHECK(CalledOnValidThread()); 125 DCHECK(CalledOnValidThread());
109 user_callbacks_.push_back(user_callback); 126 user_callbacks_.push_back(user_callback);
110 } 127 }
111 128
112 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() { 129 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() {
113 DCHECK(CalledOnValidThread()); 130 DCHECK(CalledOnValidThread());
114 return attachment_; 131 return attachment_;
115 } 132 }
116 133
117 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete( 134 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
118 const net::URLFetcher* source) { 135 const net::URLFetcher* source) {
119 DCHECK(CalledOnValidThread()); 136 DCHECK(CalledOnValidThread());
120 // TODO(maniscalco): Once the protocol is better defined, deal with the
121 // various HTTP response code we may encounter.
122 UploadResult result = UPLOAD_UNSPECIFIED_ERROR; 137 UploadResult result = UPLOAD_UNSPECIFIED_ERROR;
138 AttachmentId attachment_id = attachment_.GetId();
123 if (source->GetResponseCode() == net::HTTP_OK) { 139 if (source->GetResponseCode() == net::HTTP_OK) {
124 result = UPLOAD_SUCCESS; 140 result = UPLOAD_SUCCESS;
141 // TODO(maniscalco): Update the attachment id with server address
142 // information before passing it to the callback (bug 371522).
143 } else if (source->GetResponseCode() == net::HTTP_UNAUTHORIZED) {
144 OAuth2TokenServiceRequest::InvalidateToken(
145 token_service_provider_, account_id_, scopes_, access_token_);
pavely 2014/06/03 17:38:54 This is likely transient error. It might mean that
maniscalco 2014/06/04 00:20:50 Done.
146 } else {
147 // TODO(maniscalco): Once the protocol is better defined, deal with the
148 // various HTTP response codes we may encounter.
125 } 149 }
126 // TODO(maniscalco): Update the attachment id with server address information 150 ReportResult(result, attachment_id);
127 // before passing it to the callback (bug 371522). 151 }
128 AttachmentId updated_id = attachment_.GetId(); 152
153 void AttachmentUploaderImpl::UploadState::OnGetTokenSuccess(
154 const OAuth2TokenService::Request* request,
155 const std::string& access_token,
156 const base::Time& expiration_time) {
157 DCHECK_EQ(access_token_request_.get(), request);
158 access_token_request_.reset();
159 access_token_ = access_token;
160 fetcher_.reset(
161 net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this));
162 fetcher_->SetRequestContext(url_request_context_getter_.get());
163 // TODO(maniscalco): Is there a better way? Copying the attachment data into
164 // a string feels wrong given how large attachments may be (several MBs). If
165 // we may end up switching from URLFetcher to URLRequest, this copy won't be
166 // necessary.
167 scoped_refptr<base::RefCountedMemory> memory = attachment_.GetData();
168 const std::string upload_content(memory->front_as<char>(), memory->size());
169 fetcher_->SetUploadData(kContentType, upload_content);
170 const std::string auth_header("Authorization: Bearer " + access_token_);
171 fetcher_->AddExtraRequestHeader(auth_header);
172 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
173 net::LOAD_DO_NOT_SEND_COOKIES |
174 net::LOAD_DISABLE_CACHE);
175 // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and
176 // Content-length) on the request and include the content's MD5,
177 // AttachmentId's unique_id and the "sync birthday" (bug 371521).
178 fetcher_->Start();
179 }
180
181 void AttachmentUploaderImpl::UploadState::OnGetTokenFailure(
182 const OAuth2TokenService::Request* request,
183 const GoogleServiceAuthError& error) {
184 DCHECK_EQ(access_token_request_.get(), request);
185 access_token_request_.reset();
186 ReportResult(UPLOAD_UNSPECIFIED_ERROR, attachment_.GetId());
187 }
188
189 void AttachmentUploaderImpl::UploadState::GetToken() {
pavely 2014/06/03 17:38:54 [nothing to change here]. It is unfortunate that s
maniscalco 2014/06/04 00:20:50 Agreed. On 2014/06/03 17:38:54, pavely wrote:
190 access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart(
191 token_service_provider_, account_id_, scopes_, this);
192 }
193
194 void AttachmentUploaderImpl::UploadState::ReportResult(
195 const UploadResult& result,
196 const AttachmentId& attachment_id) {
129 UploadCallbackList::const_iterator iter = user_callbacks_.begin(); 197 UploadCallbackList::const_iterator iter = user_callbacks_.begin();
130 UploadCallbackList::const_iterator end = user_callbacks_.end(); 198 UploadCallbackList::const_iterator end = user_callbacks_.end();
131 for (; iter != end; ++iter) { 199 for (; iter != end; ++iter) {
132 base::MessageLoop::current()->PostTask( 200 base::MessageLoop::current()->PostTask(
133 FROM_HERE, base::Bind(*iter, result, updated_id)); 201 FROM_HERE, base::Bind(*iter, result, attachment_id));
134 } 202 }
135 // Destroy this object and return immediately. 203 // Destroy this object and return immediately.
136 owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id()); 204 owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id());
137 return; 205 return;
138 } 206 }
139 207
140 AttachmentUploaderImpl::AttachmentUploaderImpl( 208 AttachmentUploaderImpl::AttachmentUploaderImpl(
141 const std::string& url_prefix, 209 const std::string& url_prefix,
142 const scoped_refptr<net::URLRequestContextGetter>& 210 const scoped_refptr<net::URLRequestContextGetter>&
143 url_request_context_getter) 211 url_request_context_getter,
212 const std::string& account_id,
213 scoped_ptr<OAuth2TokenServiceRequest::TokenServiceProvider>
214 token_service_provider)
144 : url_prefix_(url_prefix), 215 : url_prefix_(url_prefix),
145 url_request_context_getter_(url_request_context_getter) { 216 url_request_context_getter_(url_request_context_getter),
217 account_id_(account_id),
218 token_service_provider_(token_service_provider.Pass()) {
146 DCHECK(CalledOnValidThread()); 219 DCHECK(CalledOnValidThread());
220 DCHECK(token_service_provider_);
147 } 221 }
148 222
149 AttachmentUploaderImpl::~AttachmentUploaderImpl() { 223 AttachmentUploaderImpl::~AttachmentUploaderImpl() {
150 DCHECK(CalledOnValidThread()); 224 DCHECK(CalledOnValidThread());
151 } 225 }
152 226
153 void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment, 227 void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment,
154 const UploadCallback& callback) { 228 const UploadCallback& callback) {
155 DCHECK(CalledOnValidThread()); 229 DCHECK(CalledOnValidThread());
156 const AttachmentId attachment_id = attachment.GetId(); 230 const AttachmentId attachment_id = attachment.GetId();
157 const std::string unique_id = attachment_id.GetProto().unique_id(); 231 const std::string unique_id = attachment_id.GetProto().unique_id();
158 DCHECK(!unique_id.empty()); 232 DCHECK(!unique_id.empty());
159 StateMap::iterator iter = state_map_.find(unique_id); 233 StateMap::iterator iter = state_map_.find(unique_id);
160 if (iter == state_map_.end()) { 234 if (iter == state_map_.end()) {
161 const GURL url = GetUploadURLForAttachmentId(attachment_id); 235 const GURL url = GetUploadURLForAttachmentId(attachment_id);
162 scoped_ptr<UploadState> upload_state(new UploadState( 236 scoped_ptr<UploadState> upload_state(
163 url, url_request_context_getter_, attachment, callback, this)); 237 new UploadState(url,
238 url_request_context_getter_,
239 attachment,
240 callback,
241 account_id_,
242 token_service_provider_.get(),
243 this));
164 state_map_.add(unique_id, upload_state.Pass()); 244 state_map_.add(unique_id, upload_state.Pass());
165 } else { 245 } else {
166 DCHECK( 246 DCHECK(
167 attachment.GetData()->Equals(iter->second->GetAttachment().GetData())); 247 attachment.GetData()->Equals(iter->second->GetAttachment().GetData()));
168 // We already have an upload for this attachment. "Join" it. 248 // We already have an upload for this attachment. "Join" it.
169 iter->second->AddUserCallback(callback); 249 iter->second->AddUserCallback(callback);
170 } 250 }
171 } 251 }
172 252
173 GURL AttachmentUploaderImpl::GetUploadURLForAttachmentId( 253 GURL AttachmentUploaderImpl::GetUploadURLForAttachmentId(
174 const AttachmentId& attachment_id) const { 254 const AttachmentId& attachment_id) const {
175 return GURL(url_prefix_ + attachment_id.GetProto().unique_id()); 255 return GURL(url_prefix_ + attachment_id.GetProto().unique_id());
176 } 256 }
177 257
178 void AttachmentUploaderImpl::DeleteUploadStateFor(const UniqueId& unique_id) { 258 void AttachmentUploaderImpl::DeleteUploadStateFor(const UniqueId& unique_id) {
179 state_map_.erase(unique_id); 259 state_map_.erase(unique_id);
180 } 260 }
181 261
182 } // namespace syncer 262 } // namespace syncer
OLDNEW
« no previous file with comments | « no previous file | sync/internal_api/attachments/attachment_uploader_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698