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/drive_api_service.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/sequenced_task_runner.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/task_runner_util.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/drive/drive_api_util.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "google_apis/drive/auth_service.h"
     18 #include "google_apis/drive/drive_api_parser.h"
     19 #include "google_apis/drive/drive_api_requests.h"
     20 #include "google_apis/drive/gdata_errorcode.h"
     21 #include "google_apis/drive/gdata_wapi_parser.h"
     22 #include "google_apis/drive/gdata_wapi_requests.h"
     23 #include "google_apis/drive/request_sender.h"
     24 #include "google_apis/google_api_keys.h"
     25 #include "net/url_request/url_request_context_getter.h"
     26 
     27 using content::BrowserThread;
     28 using google_apis::AboutResourceCallback;
     29 using google_apis::AppList;
     30 using google_apis::AppListCallback;
     31 using google_apis::AuthStatusCallback;
     32 using google_apis::AuthorizeAppCallback;
     33 using google_apis::CancelCallback;
     34 using google_apis::ChangeList;
     35 using google_apis::ChangeListCallback;
     36 using google_apis::DownloadActionCallback;
     37 using google_apis::EntryActionCallback;
     38 using google_apis::FileList;
     39 using google_apis::FileListCallback;
     40 using google_apis::FileResource;
     41 using google_apis::FileResourceCallback;
     42 using google_apis::GDATA_OTHER_ERROR;
     43 using google_apis::GDATA_PARSE_ERROR;
     44 using google_apis::GDataErrorCode;
     45 using google_apis::GetContentCallback;
     46 using google_apis::GetResourceEntryRequest;
     47 using google_apis::GetShareUrlCallback;
     48 using google_apis::HTTP_NOT_IMPLEMENTED;
     49 using google_apis::HTTP_SUCCESS;
     50 using google_apis::InitiateUploadCallback;
     51 using google_apis::Link;
     52 using google_apis::ProgressCallback;
     53 using google_apis::RequestSender;
     54 using google_apis::UploadRangeResponse;
     55 using google_apis::drive::AboutGetRequest;
     56 using google_apis::drive::AppsListRequest;
     57 using google_apis::drive::ChangesListRequest;
     58 using google_apis::drive::ChangesListNextPageRequest;
     59 using google_apis::drive::ChildrenDeleteRequest;
     60 using google_apis::drive::ChildrenInsertRequest;
     61 using google_apis::drive::DownloadFileRequest;
     62 using google_apis::drive::FilesCopyRequest;
     63 using google_apis::drive::FilesGetRequest;
     64 using google_apis::drive::FilesInsertRequest;
     65 using google_apis::drive::FilesPatchRequest;
     66 using google_apis::drive::FilesListRequest;
     67 using google_apis::drive::FilesListNextPageRequest;
     68 using google_apis::drive::FilesDeleteRequest;
     69 using google_apis::drive::FilesTrashRequest;
     70 using google_apis::drive::GetUploadStatusRequest;
     71 using google_apis::drive::InitiateUploadExistingFileRequest;
     72 using google_apis::drive::InitiateUploadNewFileRequest;
     73 using google_apis::drive::ResumeUploadRequest;
     74 using google_apis::drive::UploadRangeCallback;
     75 
     76 namespace drive {
     77 
     78 namespace {
     79 
     80 // OAuth2 scopes for Drive API.
     81 const char kDriveScope[] = "https://www.googleapis.com/auth/drive";
     82 const char kDriveAppsReadonlyScope[] =
     83     "https://www.googleapis.com/auth/drive.apps.readonly";
     84 
     85 // Mime type to create a directory.
     86 const char kFolderMimeType[] = "application/vnd.google-apps.folder";
     87 
     88 // Max number of file entries to be fetched in a single http request.
     89 //
     90 // The larger the number is,
     91 // - The total running time to fetch the whole file list will become shorter.
     92 // - The running time for a single request tends to become longer.
     93 // Since the file list fetching is a completely background task, for our side,
     94 // only the total time matters. However, the server seems to have a time limit
     95 // per single request, which disables us to set the largest value (1000).
     96 // TODO(kinaba): make it larger when the server gets faster.
     97 const int kMaxNumFilesResourcePerRequest = 300;
     98 const int kMaxNumFilesResourcePerRequestForSearch = 100;
     99 
    100 // For performance, we declare all fields we use.
    101 const char kAboutResourceFields[] =
    102     "kind,quotaBytesTotal,quotaBytesUsed,largestChangeId,rootFolderId";
    103 const char kFileResourceFields[] =
    104     "kind,id,title,createdDate,sharedWithMeDate,mimeType,"
    105     "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
    106     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
    107     "parents(id,parentLink),alternateLink,"
    108     "modifiedDate,lastViewedByMeDate,shared";
    109 const char kFileResourceOpenWithLinksFields[] =
    110     "kind,id,openWithLinks/*";
    111 const char kFileListFields[] =
    112     "kind,items(kind,id,title,createdDate,sharedWithMeDate,"
    113     "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
    114     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
    115     "parents(id,parentLink),alternateLink,"
    116     "modifiedDate,lastViewedByMeDate,shared),nextLink";
    117 const char kChangeListFields[] =
    118     "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,"
    119     "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
    120     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
    121     "parents(id,parentLink),alternateLink,modifiedDate,"
    122     "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink,"
    123     "largestChangeId";
    124 
    125 void ExtractOpenUrlAndRun(const std::string& app_id,
    126                           const AuthorizeAppCallback& callback,
    127                           GDataErrorCode error,
    128                           scoped_ptr<FileResource> value) {
    129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    130   DCHECK(!callback.is_null());
    131 
    132   if (!value) {
    133     callback.Run(error, GURL());
    134     return;
    135   }
    136 
    137   const std::vector<FileResource::OpenWithLink>& open_with_links =
    138       value->open_with_links();
    139   for (size_t i = 0; i < open_with_links.size(); ++i) {
    140     if (open_with_links[i].app_id == app_id) {
    141       callback.Run(HTTP_SUCCESS, open_with_links[i].open_url);
    142       return;
    143     }
    144   }
    145 
    146   // Not found.
    147   callback.Run(GDATA_OTHER_ERROR, GURL());
    148 }
    149 
    150 // Ignores the |entry|, and runs the |callback|.
    151 void EntryActionCallbackAdapter(
    152     const EntryActionCallback& callback,
    153     GDataErrorCode error, scoped_ptr<FileResource> entry) {
    154   callback.Run(error);
    155 }
    156 
    157 // The resource ID for the root directory for Drive API is defined in the spec:
    158 // https://developers.google.com/drive/folder
    159 const char kDriveApiRootDirectoryResourceId[] = "root";
    160 
    161 }  // namespace
    162 
    163 DriveAPIService::DriveAPIService(
    164     OAuth2TokenService* oauth2_token_service,
    165     net::URLRequestContextGetter* url_request_context_getter,
    166     base::SequencedTaskRunner* blocking_task_runner,
    167     const GURL& base_url,
    168     const GURL& base_download_url,
    169     const GURL& wapi_base_url,
    170     const std::string& custom_user_agent)
    171     : oauth2_token_service_(oauth2_token_service),
    172       url_request_context_getter_(url_request_context_getter),
    173       blocking_task_runner_(blocking_task_runner),
    174       url_generator_(base_url, base_download_url),
    175       wapi_url_generator_(wapi_base_url),
    176       custom_user_agent_(custom_user_agent) {
    177   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    178 }
    179 
    180 DriveAPIService::~DriveAPIService() {
    181   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    182   if (sender_.get())
    183     sender_->auth_service()->RemoveObserver(this);
    184 }
    185 
    186 void DriveAPIService::Initialize(const std::string& account_id) {
    187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    188 
    189   std::vector<std::string> scopes;
    190   scopes.push_back(kDriveScope);
    191   scopes.push_back(kDriveAppsReadonlyScope);
    192   scopes.push_back(util::kDriveAppsScope);
    193 
    194   // GData WAPI token for GetShareUrl().
    195   scopes.push_back(util::kDocsListScope);
    196 
    197   sender_.reset(new RequestSender(
    198       new google_apis::AuthService(oauth2_token_service_,
    199                                    account_id,
    200                                    url_request_context_getter_.get(),
    201                                    scopes),
    202       url_request_context_getter_.get(),
    203       blocking_task_runner_.get(),
    204       custom_user_agent_));
    205   sender_->auth_service()->AddObserver(this);
    206 }
    207 
    208 void DriveAPIService::AddObserver(DriveServiceObserver* observer) {
    209   observers_.AddObserver(observer);
    210 }
    211 
    212 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) {
    213   observers_.RemoveObserver(observer);
    214 }
    215 
    216 bool DriveAPIService::CanSendRequest() const {
    217   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    218 
    219   return HasRefreshToken();
    220 }
    221 
    222 ResourceIdCanonicalizer DriveAPIService::GetResourceIdCanonicalizer() const {
    223   return base::Bind(&drive::util::CanonicalizeResourceId);
    224 }
    225 
    226 std::string DriveAPIService::GetRootResourceId() const {
    227   return kDriveApiRootDirectoryResourceId;
    228 }
    229 
    230 CancelCallback DriveAPIService::GetAllFileList(
    231     const FileListCallback& callback) {
    232   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    233   DCHECK(!callback.is_null());
    234 
    235   FilesListRequest* request = new FilesListRequest(
    236       sender_.get(), url_generator_, callback);
    237   request->set_max_results(kMaxNumFilesResourcePerRequest);
    238   request->set_q("trashed = false");  // Exclude trashed files.
    239   request->set_fields(kFileListFields);
    240   return sender_->StartRequestWithRetry(request);
    241 }
    242 
    243 CancelCallback DriveAPIService::GetFileListInDirectory(
    244     const std::string& directory_resource_id,
    245     const FileListCallback& callback) {
    246   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    247   DCHECK(!directory_resource_id.empty());
    248   DCHECK(!callback.is_null());
    249 
    250   // Because children.list method on Drive API v2 returns only the list of
    251   // children's references, but we need all file resource list.
    252   // So, here we use files.list method instead, with setting parents query.
    253   // After the migration from GData WAPI to Drive API v2, we should clean the
    254   // code up by moving the responsibility to include "parents" in the query
    255   // to client side.
    256   // We aren't interested in files in trash in this context, neither.
    257   FilesListRequest* request = new FilesListRequest(
    258       sender_.get(), url_generator_, callback);
    259   request->set_max_results(kMaxNumFilesResourcePerRequest);
    260   request->set_q(base::StringPrintf(
    261       "'%s' in parents and trashed = false",
    262       drive::util::EscapeQueryStringValue(directory_resource_id).c_str()));
    263   request->set_fields(kFileListFields);
    264   return sender_->StartRequestWithRetry(request);
    265 }
    266 
    267 CancelCallback DriveAPIService::Search(
    268     const std::string& search_query,
    269     const FileListCallback& callback) {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271   DCHECK(!search_query.empty());
    272   DCHECK(!callback.is_null());
    273 
    274   FilesListRequest* request = new FilesListRequest(
    275       sender_.get(), url_generator_, callback);
    276   request->set_max_results(kMaxNumFilesResourcePerRequestForSearch);
    277   request->set_q(drive::util::TranslateQuery(search_query));
    278   request->set_fields(kFileListFields);
    279   return sender_->StartRequestWithRetry(request);
    280 }
    281 
    282 CancelCallback DriveAPIService::SearchByTitle(
    283     const std::string& title,
    284     const std::string& directory_resource_id,
    285     const FileListCallback& callback) {
    286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    287   DCHECK(!title.empty());
    288   DCHECK(!callback.is_null());
    289 
    290   std::string query;
    291   base::StringAppendF(&query, "title = '%s'",
    292                       drive::util::EscapeQueryStringValue(title).c_str());
    293   if (!directory_resource_id.empty()) {
    294     base::StringAppendF(
    295         &query, " and '%s' in parents",
    296         drive::util::EscapeQueryStringValue(directory_resource_id).c_str());
    297   }
    298   query += " and trashed = false";
    299 
    300   FilesListRequest* request = new FilesListRequest(
    301       sender_.get(), url_generator_, callback);
    302   request->set_max_results(kMaxNumFilesResourcePerRequest);
    303   request->set_q(query);
    304   request->set_fields(kFileListFields);
    305   return sender_->StartRequestWithRetry(request);
    306 }
    307 
    308 CancelCallback DriveAPIService::GetChangeList(
    309     int64 start_changestamp,
    310     const ChangeListCallback& callback) {
    311   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    312   DCHECK(!callback.is_null());
    313 
    314   ChangesListRequest* request = new ChangesListRequest(
    315       sender_.get(), url_generator_, callback);
    316   request->set_max_results(kMaxNumFilesResourcePerRequest);
    317   request->set_start_change_id(start_changestamp);
    318   request->set_fields(kChangeListFields);
    319   return sender_->StartRequestWithRetry(request);
    320 }
    321 
    322 CancelCallback DriveAPIService::GetRemainingChangeList(
    323     const GURL& next_link,
    324     const ChangeListCallback& callback) {
    325   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    326   DCHECK(!next_link.is_empty());
    327   DCHECK(!callback.is_null());
    328 
    329   ChangesListNextPageRequest* request = new ChangesListNextPageRequest(
    330       sender_.get(), callback);
    331   request->set_next_link(next_link);
    332   request->set_fields(kChangeListFields);
    333   return sender_->StartRequestWithRetry(request);
    334 }
    335 
    336 CancelCallback DriveAPIService::GetRemainingFileList(
    337     const GURL& next_link,
    338     const FileListCallback& callback) {
    339   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    340   DCHECK(!next_link.is_empty());
    341   DCHECK(!callback.is_null());
    342 
    343   FilesListNextPageRequest* request = new FilesListNextPageRequest(
    344       sender_.get(), callback);
    345   request->set_next_link(next_link);
    346   request->set_fields(kFileListFields);
    347   return sender_->StartRequestWithRetry(request);
    348 }
    349 
    350 CancelCallback DriveAPIService::GetFileResource(
    351     const std::string& resource_id,
    352     const FileResourceCallback& callback) {
    353   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    354   DCHECK(!callback.is_null());
    355 
    356   FilesGetRequest* request = new FilesGetRequest(
    357       sender_.get(), url_generator_, callback);
    358   request->set_file_id(resource_id);
    359   request->set_fields(kFileResourceFields);
    360   return sender_->StartRequestWithRetry(request);
    361 }
    362 
    363 CancelCallback DriveAPIService::GetShareUrl(
    364     const std::string& resource_id,
    365     const GURL& embed_origin,
    366     const GetShareUrlCallback& callback) {
    367   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    368   DCHECK(!callback.is_null());
    369 
    370   // Unfortunately "share url" is not yet supported on Drive API v2.
    371   // So, as a fallback, we use GData WAPI protocol for this method.
    372   // TODO(hidehiko): Get rid of this implementation when share url is
    373   // supported on Drive API v2.
    374   return sender_->StartRequestWithRetry(
    375       new GetResourceEntryRequest(sender_.get(),
    376                                   wapi_url_generator_,
    377                                   resource_id,
    378                                   embed_origin,
    379                                   base::Bind(&util::ParseShareUrlAndRun,
    380                                              callback)));
    381 }
    382 
    383 CancelCallback DriveAPIService::GetAboutResource(
    384     const AboutResourceCallback& callback) {
    385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    386   DCHECK(!callback.is_null());
    387 
    388   AboutGetRequest* request =
    389       new AboutGetRequest(sender_.get(), url_generator_, callback);
    390   request->set_fields(kAboutResourceFields);
    391   return sender_->StartRequestWithRetry(request);
    392 }
    393 
    394 CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) {
    395   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    396   DCHECK(!callback.is_null());
    397 
    398   return sender_->StartRequestWithRetry(
    399       new AppsListRequest(sender_.get(), url_generator_,
    400                           google_apis::IsGoogleChromeAPIKeyUsed(),
    401                           callback));
    402 }
    403 
    404 CancelCallback DriveAPIService::DownloadFile(
    405     const base::FilePath& local_cache_path,
    406     const std::string& resource_id,
    407     const DownloadActionCallback& download_action_callback,
    408     const GetContentCallback& get_content_callback,
    409     const ProgressCallback& progress_callback) {
    410   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    411   DCHECK(!download_action_callback.is_null());
    412   // get_content_callback may be null.
    413 
    414   return sender_->StartRequestWithRetry(
    415       new DownloadFileRequest(sender_.get(),
    416                               url_generator_,
    417                               resource_id,
    418                               local_cache_path,
    419                               download_action_callback,
    420                               get_content_callback,
    421                               progress_callback));
    422 }
    423 
    424 CancelCallback DriveAPIService::DeleteResource(
    425     const std::string& resource_id,
    426     const std::string& etag,
    427     const EntryActionCallback& callback) {
    428   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    429   DCHECK(!callback.is_null());
    430 
    431   FilesDeleteRequest* request = new FilesDeleteRequest(
    432       sender_.get(), url_generator_, callback);
    433   request->set_file_id(resource_id);
    434   request->set_etag(etag);
    435   return sender_->StartRequestWithRetry(request);
    436 }
    437 
    438 CancelCallback DriveAPIService::TrashResource(
    439     const std::string& resource_id,
    440     const EntryActionCallback& callback) {
    441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    442   DCHECK(!callback.is_null());
    443 
    444   FilesTrashRequest* request = new FilesTrashRequest(
    445       sender_.get(), url_generator_,
    446       base::Bind(&EntryActionCallbackAdapter, callback));
    447   request->set_file_id(resource_id);
    448   request->set_fields(kFileResourceFields);
    449   return sender_->StartRequestWithRetry(request);
    450 }
    451 
    452 CancelCallback DriveAPIService::AddNewDirectory(
    453     const std::string& parent_resource_id,
    454     const std::string& directory_title,
    455     const AddNewDirectoryOptions& options,
    456     const FileResourceCallback& callback) {
    457   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    458   DCHECK(!callback.is_null());
    459 
    460   FilesInsertRequest* request = new FilesInsertRequest(
    461       sender_.get(), url_generator_, callback);
    462   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
    463   request->set_mime_type(kFolderMimeType);
    464   request->set_modified_date(options.modified_date);
    465   request->add_parent(parent_resource_id);
    466   request->set_title(directory_title);
    467   request->set_fields(kFileResourceFields);
    468   return sender_->StartRequestWithRetry(request);
    469 }
    470 
    471 CancelCallback DriveAPIService::CopyResource(
    472     const std::string& resource_id,
    473     const std::string& parent_resource_id,
    474     const std::string& new_title,
    475     const base::Time& last_modified,
    476     const FileResourceCallback& callback) {
    477   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    478   DCHECK(!callback.is_null());
    479 
    480   FilesCopyRequest* request = new FilesCopyRequest(
    481       sender_.get(), url_generator_, callback);
    482   request->set_file_id(resource_id);
    483   request->add_parent(parent_resource_id);
    484   request->set_title(new_title);
    485   request->set_modified_date(last_modified);
    486   request->set_fields(kFileResourceFields);
    487   return sender_->StartRequestWithRetry(request);
    488 }
    489 
    490 CancelCallback DriveAPIService::UpdateResource(
    491     const std::string& resource_id,
    492     const std::string& parent_resource_id,
    493     const std::string& new_title,
    494     const base::Time& last_modified,
    495     const base::Time& last_viewed_by_me,
    496     const FileResourceCallback& callback) {
    497   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    498   DCHECK(!callback.is_null());
    499 
    500   FilesPatchRequest* request = new FilesPatchRequest(
    501       sender_.get(), url_generator_, callback);
    502   request->set_file_id(resource_id);
    503   request->set_title(new_title);
    504   if (!parent_resource_id.empty())
    505     request->add_parent(parent_resource_id);
    506   if (!last_modified.is_null()) {
    507     // Need to set setModifiedDate to true to overwrite modifiedDate.
    508     request->set_set_modified_date(true);
    509     request->set_modified_date(last_modified);
    510   }
    511   if (!last_viewed_by_me.is_null()) {
    512     // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
    513     // will be set to the request time (not the specified time via request).
    514     request->set_update_viewed_date(false);
    515     request->set_last_viewed_by_me_date(last_viewed_by_me);
    516   }
    517   request->set_fields(kFileResourceFields);
    518   return sender_->StartRequestWithRetry(request);
    519 }
    520 
    521 CancelCallback DriveAPIService::RenameResource(
    522     const std::string& resource_id,
    523     const std::string& new_title,
    524     const EntryActionCallback& callback) {
    525   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    526   DCHECK(!callback.is_null());
    527 
    528   FilesPatchRequest* request = new FilesPatchRequest(
    529       sender_.get(), url_generator_,
    530       base::Bind(&EntryActionCallbackAdapter, callback));
    531   request->set_file_id(resource_id);
    532   request->set_title(new_title);
    533   request->set_fields(kFileResourceFields);
    534   return sender_->StartRequestWithRetry(request);
    535 }
    536 
    537 CancelCallback DriveAPIService::AddResourceToDirectory(
    538     const std::string& parent_resource_id,
    539     const std::string& resource_id,
    540     const EntryActionCallback& callback) {
    541   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    542   DCHECK(!callback.is_null());
    543 
    544   ChildrenInsertRequest* request =
    545       new ChildrenInsertRequest(sender_.get(), url_generator_, callback);
    546   request->set_folder_id(parent_resource_id);
    547   request->set_id(resource_id);
    548   return sender_->StartRequestWithRetry(request);
    549 }
    550 
    551 CancelCallback DriveAPIService::RemoveResourceFromDirectory(
    552     const std::string& parent_resource_id,
    553     const std::string& resource_id,
    554     const EntryActionCallback& callback) {
    555   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    556   DCHECK(!callback.is_null());
    557 
    558   ChildrenDeleteRequest* request =
    559       new ChildrenDeleteRequest(sender_.get(), url_generator_, callback);
    560   request->set_child_id(resource_id);
    561   request->set_folder_id(parent_resource_id);
    562   return sender_->StartRequestWithRetry(request);
    563 }
    564 
    565 CancelCallback DriveAPIService::InitiateUploadNewFile(
    566     const std::string& content_type,
    567     int64 content_length,
    568     const std::string& parent_resource_id,
    569     const std::string& title,
    570     const InitiateUploadNewFileOptions& options,
    571     const InitiateUploadCallback& callback) {
    572   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    573   DCHECK(!callback.is_null());
    574 
    575   InitiateUploadNewFileRequest* request =
    576       new InitiateUploadNewFileRequest(sender_.get(),
    577                                        url_generator_,
    578                                        content_type,
    579                                        content_length,
    580                                        parent_resource_id,
    581                                        title,
    582                                        callback);
    583   request->set_modified_date(options.modified_date);
    584   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
    585   return sender_->StartRequestWithRetry(request);
    586 }
    587 
    588 CancelCallback DriveAPIService::InitiateUploadExistingFile(
    589     const std::string& content_type,
    590     int64 content_length,
    591     const std::string& resource_id,
    592     const InitiateUploadExistingFileOptions& options,
    593     const InitiateUploadCallback& callback) {
    594   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    595   DCHECK(!callback.is_null());
    596 
    597   InitiateUploadExistingFileRequest* request =
    598       new InitiateUploadExistingFileRequest(sender_.get(),
    599                                             url_generator_,
    600                                             content_type,
    601                                             content_length,
    602                                             resource_id,
    603                                             options.etag,
    604                                             callback);
    605   request->set_parent_resource_id(options.parent_resource_id);
    606   request->set_title(options.title);
    607   request->set_modified_date(options.modified_date);
    608   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
    609   return sender_->StartRequestWithRetry(request);
    610 }
    611 
    612 CancelCallback DriveAPIService::ResumeUpload(
    613     const GURL& upload_url,
    614     int64 start_position,
    615     int64 end_position,
    616     int64 content_length,
    617     const std::string& content_type,
    618     const base::FilePath& local_file_path,
    619     const UploadRangeCallback& callback,
    620     const ProgressCallback& progress_callback) {
    621   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    622   DCHECK(!callback.is_null());
    623 
    624   return sender_->StartRequestWithRetry(
    625       new ResumeUploadRequest(
    626           sender_.get(),
    627           upload_url,
    628           start_position,
    629           end_position,
    630           content_length,
    631           content_type,
    632           local_file_path,
    633           callback,
    634           progress_callback));
    635 }
    636 
    637 CancelCallback DriveAPIService::GetUploadStatus(
    638     const GURL& upload_url,
    639     int64 content_length,
    640     const UploadRangeCallback& callback) {
    641   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    642   DCHECK(!callback.is_null());
    643 
    644   return sender_->StartRequestWithRetry(new GetUploadStatusRequest(
    645       sender_.get(),
    646       upload_url,
    647       content_length,
    648       callback));
    649 }
    650 
    651 CancelCallback DriveAPIService::AuthorizeApp(
    652     const std::string& resource_id,
    653     const std::string& app_id,
    654     const AuthorizeAppCallback& callback) {
    655   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    656   DCHECK(!callback.is_null());
    657 
    658   // Files.Authorize is only available for whitelisted clients like official
    659   // Google Chrome. In other cases, we fall back to Files.Get that returns the
    660   // same value as Files.Authorize without doing authorization. In that case,
    661   // the app can open if it was authorized by other means (from whitelisted
    662   // clients or drive.google.com web UI.)
    663   if (google_apis::IsGoogleChromeAPIKeyUsed()) {
    664     google_apis::drive::FilesAuthorizeRequest* request =
    665         new google_apis::drive::FilesAuthorizeRequest(
    666             sender_.get(), url_generator_,
    667             base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
    668     request->set_app_id(app_id);
    669     request->set_file_id(resource_id);
    670     request->set_fields(kFileResourceOpenWithLinksFields);
    671     return sender_->StartRequestWithRetry(request);
    672   } else {
    673     FilesGetRequest* request = new FilesGetRequest(
    674         sender_.get(), url_generator_,
    675         base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
    676     request->set_file_id(resource_id);
    677     request->set_fields(kFileResourceOpenWithLinksFields);
    678     return sender_->StartRequestWithRetry(request);
    679   }
    680 }
    681 
    682 CancelCallback DriveAPIService::UninstallApp(
    683     const std::string& app_id,
    684     const google_apis::EntryActionCallback& callback) {
    685   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    686   DCHECK(!callback.is_null());
    687 
    688   google_apis::drive::AppsDeleteRequest* request =
    689       new google_apis::drive::AppsDeleteRequest(sender_.get(), url_generator_,
    690                                                 callback);
    691   request->set_app_id(app_id);
    692   return sender_->StartRequestWithRetry(request);
    693 }
    694 
    695 google_apis::CancelCallback DriveAPIService::AddPermission(
    696     const std::string& resource_id,
    697     const std::string& email,
    698     google_apis::drive::PermissionRole role,
    699     const google_apis::EntryActionCallback& callback) {
    700   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    701   DCHECK(!callback.is_null());
    702 
    703   google_apis::drive::PermissionsInsertRequest* request =
    704       new google_apis::drive::PermissionsInsertRequest(sender_.get(),
    705                                                        url_generator_,
    706                                                        callback);
    707   request->set_id(resource_id);
    708   request->set_role(role);
    709   request->set_type(google_apis::drive::PERMISSION_TYPE_USER);
    710   request->set_value(email);
    711   return sender_->StartRequestWithRetry(request);
    712 }
    713 
    714 bool DriveAPIService::HasAccessToken() const {
    715   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    716   return sender_->auth_service()->HasAccessToken();
    717 }
    718 
    719 void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) {
    720   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    721   DCHECK(!callback.is_null());
    722 
    723   const std::string access_token = sender_->auth_service()->access_token();
    724   if (!access_token.empty()) {
    725     callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
    726     return;
    727   }
    728 
    729   // Retrieve the new auth token.
    730   sender_->auth_service()->StartAuthentication(callback);
    731 }
    732 
    733 bool DriveAPIService::HasRefreshToken() const {
    734   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    735   return sender_->auth_service()->HasRefreshToken();
    736 }
    737 
    738 void DriveAPIService::ClearAccessToken() {
    739   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    740   sender_->auth_service()->ClearAccessToken();
    741 }
    742 
    743 void DriveAPIService::ClearRefreshToken() {
    744   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    745   sender_->auth_service()->ClearRefreshToken();
    746 }
    747 
    748 void DriveAPIService::OnOAuth2RefreshTokenChanged() {
    749   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    750   if (CanSendRequest()) {
    751     FOR_EACH_OBSERVER(
    752         DriveServiceObserver, observers_, OnReadyToSendRequests());
    753   } else if (!HasRefreshToken()) {
    754     FOR_EACH_OBSERVER(
    755         DriveServiceObserver, observers_, OnRefreshTokenInvalid());
    756   }
    757 }
    758 
    759 }  // namespace drive
    760