• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/drive/gdata_wapi_service.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/values.h"
14 #include "chrome/browser/drive/drive_api_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/drive/auth_service.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "google_apis/drive/gdata_errorcode.h"
19 #include "google_apis/drive/gdata_wapi_parser.h"
20 #include "google_apis/drive/gdata_wapi_requests.h"
21 #include "google_apis/drive/gdata_wapi_url_generator.h"
22 #include "google_apis/drive/request_sender.h"
23 #include "net/url_request/url_request_context_getter.h"
24 
25 using content::BrowserThread;
26 using google_apis::AboutResource;
27 using google_apis::AboutResourceCallback;
28 using google_apis::AccountMetadata;
29 using google_apis::AddResourceToDirectoryRequest;
30 using google_apis::AppList;
31 using google_apis::AppListCallback;
32 using google_apis::AuthService;
33 using google_apis::AuthStatusCallback;
34 using google_apis::AuthorizeAppCallback;
35 using google_apis::AuthorizeAppRequest;
36 using google_apis::CancelCallback;
37 using google_apis::CreateDirectoryRequest;
38 using google_apis::DeleteResourceRequest;
39 using google_apis::DownloadActionCallback;
40 using google_apis::DownloadFileRequest;
41 using google_apis::EntryActionCallback;
42 using google_apis::GDATA_PARSE_ERROR;
43 using google_apis::GDataErrorCode;
44 using google_apis::GetAccountMetadataRequest;
45 using google_apis::GetContentCallback;
46 using google_apis::GetResourceEntryCallback;
47 using google_apis::GetResourceEntryRequest;
48 using google_apis::GetResourceListCallback;
49 using google_apis::GetResourceListRequest;
50 using google_apis::GetShareUrlCallback;
51 using google_apis::GetUploadStatusRequest;
52 using google_apis::HTTP_NOT_IMPLEMENTED;
53 using google_apis::InitiateUploadCallback;
54 using google_apis::InitiateUploadExistingFileRequest;
55 using google_apis::InitiateUploadNewFileRequest;
56 using google_apis::Link;
57 using google_apis::ProgressCallback;
58 using google_apis::RemoveResourceFromDirectoryRequest;
59 using google_apis::RenameResourceRequest;
60 using google_apis::RequestSender;
61 using google_apis::ResourceEntry;
62 using google_apis::ResumeUploadRequest;
63 using google_apis::SearchByTitleRequest;
64 using google_apis::UploadRangeCallback;
65 
66 namespace drive {
67 
68 namespace {
69 
70 // OAuth2 scopes for the documents API.
71 const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/";
72 const char kUserContentScope[] = "https://docs.googleusercontent.com/";
73 
74 // Parses the JSON value to ResourceEntry runs |callback|.
ParseResourceEntryAndRun(const GetResourceEntryCallback & callback,GDataErrorCode error,scoped_ptr<base::Value> value)75 void ParseResourceEntryAndRun(const GetResourceEntryCallback& callback,
76                               GDataErrorCode error,
77                               scoped_ptr<base::Value> value) {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79 
80   if (!value) {
81     callback.Run(error, scoped_ptr<ResourceEntry>());
82     return;
83   }
84 
85   // Parsing ResourceEntry is cheap enough to do on UI thread.
86   scoped_ptr<ResourceEntry> entry =
87       google_apis::ResourceEntry::ExtractAndParse(*value);
88   if (!entry) {
89     callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>());
90     return;
91   }
92 
93   callback.Run(error, entry.Pass());
94 }
95 
ConvertAboutResourceAndRun(const AboutResourceCallback & callback,GDataErrorCode error,scoped_ptr<AccountMetadata> account_metadata)96 void ConvertAboutResourceAndRun(
97     const AboutResourceCallback& callback,
98     GDataErrorCode error,
99     scoped_ptr<AccountMetadata> account_metadata) {
100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101   DCHECK(!callback.is_null());
102 
103   scoped_ptr<AboutResource> about_resource;
104   if (account_metadata) {
105     about_resource = util::ConvertAccountMetadataToAboutResource(
106         *account_metadata, util::kWapiRootDirectoryResourceId);
107   }
108 
109   callback.Run(error, about_resource.Pass());
110 }
111 
ConvertAppListAndRun(const AppListCallback & callback,GDataErrorCode error,scoped_ptr<AccountMetadata> account_metadata)112 void ConvertAppListAndRun(
113     const AppListCallback& callback,
114     GDataErrorCode error,
115     scoped_ptr<AccountMetadata> account_metadata) {
116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117   DCHECK(!callback.is_null());
118 
119   scoped_ptr<AppList> app_list;
120   if (account_metadata)
121     app_list = util::ConvertAccountMetadataToAppList(*account_metadata);
122 
123   callback.Run(error, app_list.Pass());
124 }
125 
126 }  // namespace
127 
GDataWapiService(OAuth2TokenService * oauth2_token_service,net::URLRequestContextGetter * url_request_context_getter,base::SequencedTaskRunner * blocking_task_runner,const GURL & base_url,const GURL & base_download_url,const std::string & custom_user_agent)128 GDataWapiService::GDataWapiService(
129     OAuth2TokenService* oauth2_token_service,
130     net::URLRequestContextGetter* url_request_context_getter,
131     base::SequencedTaskRunner* blocking_task_runner,
132     const GURL& base_url,
133     const GURL& base_download_url,
134     const std::string& custom_user_agent)
135     : oauth2_token_service_(oauth2_token_service),
136       url_request_context_getter_(url_request_context_getter),
137       blocking_task_runner_(blocking_task_runner),
138       url_generator_(base_url, base_download_url),
139       custom_user_agent_(custom_user_agent) {
140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 }
142 
~GDataWapiService()143 GDataWapiService::~GDataWapiService() {
144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145   if (sender_.get())
146     sender_->auth_service()->RemoveObserver(this);
147 }
148 
Initialize(const std::string & account_id)149 void GDataWapiService::Initialize(const std::string& account_id) {
150   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151 
152   std::vector<std::string> scopes;
153   scopes.push_back(util::kDocsListScope);
154   scopes.push_back(kSpreadsheetsScope);
155   scopes.push_back(kUserContentScope);
156   // Drive App scope is required for even WAPI v3 apps access.
157   scopes.push_back(util::kDriveAppsScope);
158   sender_.reset(new RequestSender(
159       new AuthService(oauth2_token_service_,
160                       account_id,
161                       url_request_context_getter_.get(),
162                       scopes),
163       url_request_context_getter_.get(),
164       blocking_task_runner_.get(),
165       custom_user_agent_));
166 
167   sender_->auth_service()->AddObserver(this);
168 }
169 
AddObserver(DriveServiceObserver * observer)170 void GDataWapiService::AddObserver(DriveServiceObserver* observer) {
171   observers_.AddObserver(observer);
172 }
173 
RemoveObserver(DriveServiceObserver * observer)174 void GDataWapiService::RemoveObserver(DriveServiceObserver* observer) {
175   observers_.RemoveObserver(observer);
176 }
177 
CanSendRequest() const178 bool GDataWapiService::CanSendRequest() const {
179   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
180 
181   return HasRefreshToken();
182 }
183 
GetResourceIdCanonicalizer() const184 ResourceIdCanonicalizer GDataWapiService::GetResourceIdCanonicalizer() const {
185   return util::GetIdentityResourceIdCanonicalizer();
186 }
187 
GetRootResourceId() const188 std::string GDataWapiService::GetRootResourceId() const {
189   return util::kWapiRootDirectoryResourceId;
190 }
191 
192 // Because GData WAPI support is expected to be gone somehow soon by migration
193 // to the Drive API v2, so we'll reuse GetResourceListRequest to implement
194 // following methods, instead of cleaning the request class.
195 
GetAllResourceList(const GetResourceListCallback & callback)196 CancelCallback GDataWapiService::GetAllResourceList(
197     const GetResourceListCallback& callback) {
198   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
199   DCHECK(!callback.is_null());
200 
201   return sender_->StartRequestWithRetry(
202       new GetResourceListRequest(sender_.get(),
203                                  url_generator_,
204                                  GURL(),         // No override url
205                                  0,              // start changestamp
206                                  std::string(),  // empty search query
207                                  std::string(),  // no directory resource id
208                                  callback));
209 }
210 
GetResourceListInDirectory(const std::string & directory_resource_id,const GetResourceListCallback & callback)211 CancelCallback GDataWapiService::GetResourceListInDirectory(
212     const std::string& directory_resource_id,
213     const GetResourceListCallback& callback) {
214   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215   DCHECK(!directory_resource_id.empty());
216   DCHECK(!callback.is_null());
217 
218   return sender_->StartRequestWithRetry(
219       new GetResourceListRequest(sender_.get(),
220                                  url_generator_,
221                                  GURL(),         // No override url
222                                  0,              // start changestamp
223                                  std::string(),  // empty search query
224                                  directory_resource_id,
225                                  callback));
226 }
227 
Search(const std::string & search_query,const GetResourceListCallback & callback)228 CancelCallback GDataWapiService::Search(
229     const std::string& search_query,
230     const GetResourceListCallback& callback) {
231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232   DCHECK(!search_query.empty());
233   DCHECK(!callback.is_null());
234 
235   return sender_->StartRequestWithRetry(
236       new GetResourceListRequest(sender_.get(),
237                                  url_generator_,
238                                  GURL(),         // No override url
239                                  0,              // start changestamp
240                                  search_query,
241                                  std::string(),  // no directory resource id
242                                  callback));
243 }
244 
SearchByTitle(const std::string & title,const std::string & directory_resource_id,const GetResourceListCallback & callback)245 CancelCallback GDataWapiService::SearchByTitle(
246     const std::string& title,
247     const std::string& directory_resource_id,
248     const GetResourceListCallback& callback) {
249   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250   DCHECK(!title.empty());
251   DCHECK(!callback.is_null());
252 
253   return sender_->StartRequestWithRetry(
254       new SearchByTitleRequest(sender_.get(),
255                                url_generator_,
256                                title,
257                                directory_resource_id,
258                                callback));
259 }
260 
GetChangeList(int64 start_changestamp,const GetResourceListCallback & callback)261 CancelCallback GDataWapiService::GetChangeList(
262     int64 start_changestamp,
263     const GetResourceListCallback& callback) {
264   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
265   DCHECK(!callback.is_null());
266 
267   return sender_->StartRequestWithRetry(
268       new GetResourceListRequest(sender_.get(),
269                                  url_generator_,
270                                  GURL(),         // No override url
271                                  start_changestamp,
272                                  std::string(),  // empty search query
273                                  std::string(),  // no directory resource id
274                                  callback));
275 }
276 
GetRemainingChangeList(const GURL & next_link,const GetResourceListCallback & callback)277 CancelCallback GDataWapiService::GetRemainingChangeList(
278     const GURL& next_link,
279     const GetResourceListCallback& callback) {
280   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281   DCHECK(!next_link.is_empty());
282   DCHECK(!callback.is_null());
283 
284   return GetRemainingResourceList(next_link, callback);
285 }
286 
GetRemainingFileList(const GURL & next_link,const GetResourceListCallback & callback)287 CancelCallback GDataWapiService::GetRemainingFileList(
288     const GURL& next_link,
289     const GetResourceListCallback& callback) {
290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291   DCHECK(!next_link.is_empty());
292   DCHECK(!callback.is_null());
293 
294   return GetRemainingResourceList(next_link, callback);
295 }
296 
GetResourceEntry(const std::string & resource_id,const GetResourceEntryCallback & callback)297 CancelCallback GDataWapiService::GetResourceEntry(
298     const std::string& resource_id,
299     const GetResourceEntryCallback& callback) {
300   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301   DCHECK(!callback.is_null());
302 
303   return sender_->StartRequestWithRetry(
304       new GetResourceEntryRequest(sender_.get(),
305                                   url_generator_,
306                                   resource_id,
307                                   GURL(),
308                                   base::Bind(&ParseResourceEntryAndRun,
309                                              callback)));
310 }
311 
GetShareUrl(const std::string & resource_id,const GURL & embed_origin,const GetShareUrlCallback & callback)312 CancelCallback GDataWapiService::GetShareUrl(
313     const std::string& resource_id,
314     const GURL& embed_origin,
315     const GetShareUrlCallback& callback) {
316   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317   DCHECK(!callback.is_null());
318 
319   return sender_->StartRequestWithRetry(
320       new GetResourceEntryRequest(sender_.get(),
321                                   url_generator_,
322                                   resource_id,
323                                   embed_origin,
324                                   base::Bind(&util::ParseShareUrlAndRun,
325                                              callback)));
326 }
327 
GetAboutResource(const AboutResourceCallback & callback)328 CancelCallback GDataWapiService::GetAboutResource(
329     const AboutResourceCallback& callback) {
330   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331   DCHECK(!callback.is_null());
332 
333   return sender_->StartRequestWithRetry(
334       new GetAccountMetadataRequest(
335           sender_.get(),
336           url_generator_,
337           base::Bind(&ConvertAboutResourceAndRun, callback),
338           false));  // Exclude installed apps.
339 }
340 
GetAppList(const AppListCallback & callback)341 CancelCallback GDataWapiService::GetAppList(const AppListCallback& callback) {
342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343   DCHECK(!callback.is_null());
344 
345   return sender_->StartRequestWithRetry(
346       new GetAccountMetadataRequest(sender_.get(),
347                                     url_generator_,
348                                     base::Bind(&ConvertAppListAndRun, callback),
349                                     true));  // Include installed apps.
350 }
351 
DownloadFile(const base::FilePath & local_cache_path,const std::string & resource_id,const DownloadActionCallback & download_action_callback,const GetContentCallback & get_content_callback,const ProgressCallback & progress_callback)352 CancelCallback GDataWapiService::DownloadFile(
353     const base::FilePath& local_cache_path,
354     const std::string& resource_id,
355     const DownloadActionCallback& download_action_callback,
356     const GetContentCallback& get_content_callback,
357     const ProgressCallback& progress_callback) {
358   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359   DCHECK(!download_action_callback.is_null());
360   // get_content_callback and progress_callback may be null.
361 
362   return sender_->StartRequestWithRetry(
363       new DownloadFileRequest(sender_.get(),
364                               url_generator_,
365                               download_action_callback,
366                               get_content_callback,
367                               progress_callback,
368                               resource_id,
369                               local_cache_path));
370 }
371 
DeleteResource(const std::string & resource_id,const std::string & etag,const EntryActionCallback & callback)372 CancelCallback GDataWapiService::DeleteResource(
373     const std::string& resource_id,
374     const std::string& etag,
375     const EntryActionCallback& callback) {
376   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377   DCHECK(!callback.is_null());
378 
379   NOTIMPLEMENTED();
380   callback.Run(google_apis::GDATA_OTHER_ERROR);
381   return CancelCallback();
382 }
383 
TrashResource(const std::string & resource_id,const EntryActionCallback & callback)384 CancelCallback GDataWapiService::TrashResource(
385     const std::string& resource_id,
386     const EntryActionCallback& callback) {
387   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388   DCHECK(!callback.is_null());
389 
390   const std::string empty_etag;
391   return sender_->StartRequestWithRetry(
392       new DeleteResourceRequest(sender_.get(),
393                                 url_generator_,
394                                 callback,
395                                 resource_id,
396                                 empty_etag));
397 }
398 
AddNewDirectory(const std::string & parent_resource_id,const std::string & directory_title,const GetResourceEntryCallback & callback)399 CancelCallback GDataWapiService::AddNewDirectory(
400     const std::string& parent_resource_id,
401     const std::string& directory_title,
402     const GetResourceEntryCallback& callback) {
403   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
404   DCHECK(!callback.is_null());
405 
406   return sender_->StartRequestWithRetry(
407       new CreateDirectoryRequest(sender_.get(),
408                                  url_generator_,
409                                  base::Bind(&ParseResourceEntryAndRun,
410                                             callback),
411                                  parent_resource_id,
412                                  directory_title));
413 }
414 
CopyResource(const std::string & resource_id,const std::string & parent_resource_id,const std::string & new_title,const base::Time & last_modified,const GetResourceEntryCallback & callback)415 CancelCallback GDataWapiService::CopyResource(
416     const std::string& resource_id,
417     const std::string& parent_resource_id,
418     const std::string& new_title,
419     const base::Time& last_modified,
420     const GetResourceEntryCallback& callback) {
421   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
422   DCHECK(!callback.is_null());
423 
424   // GData WAPI doesn't support "copy" of regular files.
425   // This method should never be called if GData WAPI is enabled.
426   // Instead, client code should download the file (if needed) and upload it.
427   NOTREACHED();
428   return CancelCallback();
429 }
430 
UpdateResource(const std::string & resource_id,const std::string & parent_resource_id,const std::string & new_title,const base::Time & last_modified,const base::Time & last_viewed_by_me,const google_apis::GetResourceEntryCallback & callback)431 CancelCallback GDataWapiService::UpdateResource(
432     const std::string& resource_id,
433     const std::string& parent_resource_id,
434     const std::string& new_title,
435     const base::Time& last_modified,
436     const base::Time& last_viewed_by_me,
437     const google_apis::GetResourceEntryCallback& callback) {
438   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
439   DCHECK(!callback.is_null());
440 
441   // GData WAPI doesn't support to "move" resources.
442   // This method should never be called if GData WAPI is enabled.
443   // Instead, client code should rename the file, add new parent, and then
444   // remove the old parent.
445   NOTREACHED();
446   return CancelCallback();
447 }
448 
RenameResource(const std::string & resource_id,const std::string & new_title,const EntryActionCallback & callback)449 CancelCallback GDataWapiService::RenameResource(
450     const std::string& resource_id,
451     const std::string& new_title,
452     const EntryActionCallback& callback) {
453   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454   DCHECK(!callback.is_null());
455 
456   return sender_->StartRequestWithRetry(
457       new RenameResourceRequest(sender_.get(),
458                                 url_generator_,
459                                 callback,
460                                 resource_id,
461                                 new_title));
462 }
463 
AddResourceToDirectory(const std::string & parent_resource_id,const std::string & resource_id,const EntryActionCallback & callback)464 CancelCallback GDataWapiService::AddResourceToDirectory(
465     const std::string& parent_resource_id,
466     const std::string& resource_id,
467     const EntryActionCallback& callback) {
468   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
469   DCHECK(!callback.is_null());
470 
471   return sender_->StartRequestWithRetry(
472       new AddResourceToDirectoryRequest(sender_.get(),
473                                         url_generator_,
474                                         callback,
475                                         parent_resource_id,
476                                         resource_id));
477 }
478 
RemoveResourceFromDirectory(const std::string & parent_resource_id,const std::string & resource_id,const EntryActionCallback & callback)479 CancelCallback GDataWapiService::RemoveResourceFromDirectory(
480     const std::string& parent_resource_id,
481     const std::string& resource_id,
482     const EntryActionCallback& callback) {
483   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484   DCHECK(!callback.is_null());
485 
486   return sender_->StartRequestWithRetry(
487       new RemoveResourceFromDirectoryRequest(sender_.get(),
488                                              url_generator_,
489                                              callback,
490                                              parent_resource_id,
491                                              resource_id));
492 }
493 
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const InitiateUploadCallback & callback)494 CancelCallback GDataWapiService::InitiateUploadNewFile(
495     const std::string& content_type,
496     int64 content_length,
497     const std::string& parent_resource_id,
498     const std::string& title,
499     const InitiateUploadCallback& callback) {
500   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
501   DCHECK(!callback.is_null());
502   DCHECK(!parent_resource_id.empty());
503 
504   return sender_->StartRequestWithRetry(
505       new InitiateUploadNewFileRequest(sender_.get(),
506                                        url_generator_,
507                                        callback,
508                                        content_type,
509                                        content_length,
510                                        parent_resource_id,
511                                        title));
512 }
513 
InitiateUploadExistingFile(const std::string & content_type,int64 content_length,const std::string & resource_id,const std::string & etag,const InitiateUploadCallback & callback)514 CancelCallback GDataWapiService::InitiateUploadExistingFile(
515     const std::string& content_type,
516     int64 content_length,
517     const std::string& resource_id,
518     const std::string& etag,
519     const InitiateUploadCallback& callback) {
520   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
521   DCHECK(!callback.is_null());
522   DCHECK(!resource_id.empty());
523 
524   return sender_->StartRequestWithRetry(
525       new InitiateUploadExistingFileRequest(sender_.get(),
526                                             url_generator_,
527                                             callback,
528                                             content_type,
529                                             content_length,
530                                             resource_id,
531                                             etag));
532 }
533 
ResumeUpload(const GURL & upload_url,int64 start_position,int64 end_position,int64 content_length,const std::string & content_type,const base::FilePath & local_file_path,const UploadRangeCallback & callback,const ProgressCallback & progress_callback)534 CancelCallback GDataWapiService::ResumeUpload(
535     const GURL& upload_url,
536     int64 start_position,
537     int64 end_position,
538     int64 content_length,
539     const std::string& content_type,
540     const base::FilePath& local_file_path,
541     const UploadRangeCallback& callback,
542     const ProgressCallback& progress_callback) {
543   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
544   DCHECK(!callback.is_null());
545 
546   return sender_->StartRequestWithRetry(
547       new ResumeUploadRequest(sender_.get(),
548                               callback,
549                               progress_callback,
550                               upload_url,
551                               start_position,
552                               end_position,
553                               content_length,
554                               content_type,
555                               local_file_path));
556 }
557 
GetUploadStatus(const GURL & upload_url,int64 content_length,const UploadRangeCallback & callback)558 CancelCallback GDataWapiService::GetUploadStatus(
559     const GURL& upload_url,
560     int64 content_length,
561     const UploadRangeCallback& callback) {
562   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
563   DCHECK(!callback.is_null());
564 
565   return sender_->StartRequestWithRetry(
566       new GetUploadStatusRequest(sender_.get(),
567                                  callback,
568                                  upload_url,
569                                  content_length));
570 }
571 
AuthorizeApp(const std::string & resource_id,const std::string & app_id,const AuthorizeAppCallback & callback)572 CancelCallback GDataWapiService::AuthorizeApp(
573     const std::string& resource_id,
574     const std::string& app_id,
575     const AuthorizeAppCallback& callback) {
576   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
577   DCHECK(!callback.is_null());
578 
579   return sender_->StartRequestWithRetry(
580       new AuthorizeAppRequest(sender_.get(),
581                               url_generator_,
582                               callback,
583                               resource_id,
584                               app_id));
585 }
586 
GetResourceListInDirectoryByWapi(const std::string & directory_resource_id,const google_apis::GetResourceListCallback & callback)587 CancelCallback GDataWapiService::GetResourceListInDirectoryByWapi(
588     const std::string& directory_resource_id,
589     const google_apis::GetResourceListCallback& callback) {
590   return GetResourceListInDirectory(directory_resource_id, callback);
591 }
592 
GetRemainingResourceList(const GURL & next_link,const google_apis::GetResourceListCallback & callback)593 CancelCallback GDataWapiService::GetRemainingResourceList(
594     const GURL& next_link,
595     const google_apis::GetResourceListCallback& callback) {
596   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
597   DCHECK(!next_link.is_empty());
598   DCHECK(!callback.is_null());
599 
600   return sender_->StartRequestWithRetry(
601       new GetResourceListRequest(sender_.get(),
602                                  url_generator_,
603                                  next_link,
604                                  0,              // start changestamp
605                                  std::string(),  // empty search query
606                                  std::string(),  // no directory resource id
607                                  callback));
608 }
609 
HasAccessToken() const610 bool GDataWapiService::HasAccessToken() const {
611   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612 
613   return sender_->auth_service()->HasAccessToken();
614 }
615 
RequestAccessToken(const AuthStatusCallback & callback)616 void GDataWapiService::RequestAccessToken(const AuthStatusCallback& callback) {
617   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
618   DCHECK(!callback.is_null());
619 
620   const std::string access_token = sender_->auth_service()->access_token();
621   if (!access_token.empty()) {
622     callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
623     return;
624   }
625 
626   // Retrieve the new auth token.
627   sender_->auth_service()->StartAuthentication(callback);
628 }
629 
HasRefreshToken() const630 bool GDataWapiService::HasRefreshToken() const {
631   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
632   return sender_->auth_service()->HasRefreshToken();
633 }
634 
ClearAccessToken()635 void GDataWapiService::ClearAccessToken() {
636   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
637   sender_->auth_service()->ClearAccessToken();
638 }
639 
ClearRefreshToken()640 void GDataWapiService::ClearRefreshToken() {
641   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
642   sender_->auth_service()->ClearRefreshToken();
643 }
644 
OnOAuth2RefreshTokenChanged()645 void GDataWapiService::OnOAuth2RefreshTokenChanged() {
646   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
647   if (CanSendRequest()) {
648     FOR_EACH_OBSERVER(
649         DriveServiceObserver, observers_, OnReadyToSendRequests());
650   } else if (!HasRefreshToken()) {
651     FOR_EACH_OBSERVER(
652         DriveServiceObserver, observers_, OnRefreshTokenInvalid());
653   }
654 }
655 
656 }  // namespace drive
657