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