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 "components/drive/service/drive_api_service.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/bind.h"
15 #include "base/strings/stringprintf.h"
16 #include "components/drive/drive_api_util.h"
17 #include "google_apis/drive/auth_service.h"
18 #include "google_apis/drive/base_requests.h"
19 #include "google_apis/drive/drive_api_parser.h"
20 #include "google_apis/drive/drive_api_requests.h"
21 #include "google_apis/drive/files_list_request_runner.h"
22 #include "google_apis/drive/request_sender.h"
23 #include "services/network/public/cpp/shared_url_loader_factory.h"
24 
25 using google_apis::AboutResourceCallback;
26 using google_apis::AuthStatusCallback;
27 using google_apis::CancelCallback;
28 using google_apis::CancelCallbackOnce;
29 using google_apis::CancelCallbackRepeating;
30 using google_apis::ChangeList;
31 using google_apis::ChangeListCallback;
32 using google_apis::DownloadActionCallback;
33 using google_apis::DRIVE_OTHER_ERROR;
34 using google_apis::DRIVE_PARSE_ERROR;
35 using google_apis::DriveApiErrorCode;
36 using google_apis::EntryActionCallback;
37 using google_apis::FileList;
38 using google_apis::FileListCallback;
39 using google_apis::FileResource;
40 using google_apis::FileResourceCallback;
41 using google_apis::FilesListCorpora;
42 using google_apis::FilesListRequestRunner;
43 using google_apis::GetContentCallback;
44 using google_apis::HTTP_NOT_IMPLEMENTED;
45 using google_apis::HTTP_SUCCESS;
46 using google_apis::InitiateUploadCallback;
47 using google_apis::ProgressCallback;
48 using google_apis::RequestSender;
49 using google_apis::StartPageTokenCallback;
50 using google_apis::TeamDriveListCallback;
51 using google_apis::UploadRangeResponse;
52 using google_apis::drive::AboutGetRequest;
53 using google_apis::drive::ChangesListNextPageRequest;
54 using google_apis::drive::ChangesListRequest;
55 using google_apis::drive::ChildrenDeleteRequest;
56 using google_apis::drive::ChildrenInsertRequest;
57 using google_apis::drive::DownloadFileRequest;
58 using google_apis::drive::FilesCopyRequest;
59 using google_apis::drive::FilesDeleteRequest;
60 using google_apis::drive::FilesGetRequest;
61 using google_apis::drive::FilesInsertRequest;
62 using google_apis::drive::FilesListNextPageRequest;
63 using google_apis::drive::FilesListRequest;
64 using google_apis::drive::FilesPatchRequest;
65 using google_apis::drive::FilesTrashRequest;
66 using google_apis::drive::GetUploadStatusRequest;
67 using google_apis::drive::InitiateUploadExistingFileRequest;
68 using google_apis::drive::InitiateUploadNewFileRequest;
69 using google_apis::drive::ResumeUploadRequest;
70 using google_apis::drive::StartPageTokenRequest;
71 using google_apis::drive::TeamDriveListRequest;
72 using google_apis::drive::UploadRangeCallback;
73 
74 namespace drive {
75 
76 namespace {
77 
78 // OAuth2 scopes for Drive API.
79 const char kDriveScope[] = "https://www.googleapis.com/auth/drive";
80 const char kDriveAppsReadonlyScope[] =
81     "https://www.googleapis.com/auth/drive.apps.readonly";
82 const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
83 
84 // Mime type to create a directory.
85 const char kFolderMimeType[] = "application/vnd.google-apps.folder";
86 
87 // Max number of Team Drive entries to be fetched in a single http request.
88 const int kMaxNumTeamDriveResourcePerRequest = 100;
89 
90 // Max number of file entries to be fetched in a single http request.
91 //
92 // The larger the number is,
93 // - The total running time to fetch the whole file list will become shorter.
94 // - The running time for a single request tends to become longer.
95 // Since the file list fetching is a completely background task, for our side,
96 // only the total time matters. However, the server seems to have a time limit
97 // per single request, which disables us to set the largest value (1000).
98 // TODO(kinaba): make it larger when the server gets faster.
99 const int kMaxNumFilesResourcePerRequest = 300;
100 const int kMaxNumFilesResourcePerRequestForSearch = 100;
101 
102 // For performance, we declare all fields we use.
103 const char kAboutResourceFields[] =
104     "kind,quotaBytesTotal,quotaBytesUsedAggregate,largestChangeId,rootFolderId";
105 const char kFileResourceFields[] =
106     "kind,id,title,createdDate,sharedWithMeDate,mimeType,"
107     "md5Checksum,fileSize,labels/trashed,labels/starred,"
108     "imageMediaMetadata/width,"
109     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
110     "parents(id,parentLink),alternateLink,"
111     "modifiedDate,lastViewedByMeDate,shared,modifiedByMeDate";
112 const char kFileListFields[] =
113     "kind,items(kind,id,title,createdDate,sharedWithMeDate,"
114     "mimeType,md5Checksum,fileSize,labels/trashed,labels/starred,"
115     "imageMediaMetadata/width,"
116     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
117     "parents(id,parentLink),alternateLink,"
118     "modifiedDate,lastViewedByMeDate,shared,modifiedByMeDate,capabilities),"
119     "nextLink";
120 const char kChangeListFields[] =
121     "kind,items(type,file(kind,id,title,createdDate,sharedWithMeDate,"
122     "mimeType,md5Checksum,fileSize,labels/trashed,labels/starred,"
123     "imageMediaMetadata/width,"
124     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
125     "parents(id,parentLink),alternateLink,modifiedDate,"
126     "lastViewedByMeDate,shared,modifiedByMeDate,capabilities),"
127     "teamDrive(kind,id,name,capabilities),teamDriveId,"
128     "deleted,id,fileId,modificationDate),nextLink,"
129     "largestChangeId,newStartPageToken";
130 const char kTeamDrivesListFields[] =
131     "nextPageToken,kind,items(kind,id,name,capabilities)";
132 
133 // Ignores the |entry|, and runs the |callback|.
EntryActionCallbackAdapter(EntryActionCallback callback,DriveApiErrorCode error,std::unique_ptr<FileResource> entry)134 void EntryActionCallbackAdapter(EntryActionCallback callback,
135                                 DriveApiErrorCode error,
136                                 std::unique_ptr<FileResource> entry) {
137   std::move(callback).Run(error);
138 }
139 
140 // The resource ID for the root directory for Drive API is defined in the spec:
141 // https://developers.google.com/drive/folder
142 const char kDriveApiRootDirectoryResourceId[] = "root";
143 
144 }  // namespace
145 
BatchRequestConfigurator(const base::WeakPtr<google_apis::drive::BatchUploadRequest> & batch_request,base::SequencedTaskRunner * task_runner,const google_apis::DriveApiUrlGenerator & url_generator,const google_apis::CancelCallback & cancel_callback)146 BatchRequestConfigurator::BatchRequestConfigurator(
147     const base::WeakPtr<google_apis::drive::BatchUploadRequest>& batch_request,
148     base::SequencedTaskRunner* task_runner,
149     const google_apis::DriveApiUrlGenerator& url_generator,
150     const google_apis::CancelCallback& cancel_callback)
151     : batch_request_(batch_request),
152       task_runner_(task_runner),
153       url_generator_(url_generator),
154       cancel_callback_(cancel_callback) {
155 }
156 
~BatchRequestConfigurator()157 BatchRequestConfigurator::~BatchRequestConfigurator() {
158   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
159   // The batch requst has not been committed.
160   if (batch_request_)
161     cancel_callback_.Run();
162 }
163 
164 google_apis::CancelCallbackRepeating
MultipartUploadNewFile(const std::string & content_type,int64_t content_length,const std::string & parent_resource_id,const std::string & title,const base::FilePath & local_file_path,const UploadNewFileOptions & options,FileResourceCallback callback,ProgressCallback progress_callback)165 BatchRequestConfigurator::MultipartUploadNewFile(
166     const std::string& content_type,
167     int64_t content_length,
168     const std::string& parent_resource_id,
169     const std::string& title,
170     const base::FilePath& local_file_path,
171     const UploadNewFileOptions& options,
172     FileResourceCallback callback,
173     ProgressCallback progress_callback) {
174   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
175   DCHECK(!callback.is_null());
176 
177   std::unique_ptr<google_apis::BatchableDelegate> delegate(
178       new google_apis::drive::MultipartUploadNewFileDelegate(
179           task_runner_.get(), title, parent_resource_id, content_type,
180           content_length, options.modified_date, options.last_viewed_by_me_date,
181           local_file_path, options.properties, url_generator_,
182           std::move(callback), progress_callback));
183   // Batch request can be null when pre-authorization for the requst is failed
184   // in request sender.
185   if (batch_request_)
186     batch_request_->AddRequest(delegate.release());
187   else
188     delegate->NotifyError(DRIVE_OTHER_ERROR);
189   return cancel_callback_;
190 }
191 
192 google_apis::CancelCallback
MultipartUploadExistingFile(const std::string & content_type,int64_t content_length,const std::string & resource_id,const base::FilePath & local_file_path,const UploadExistingFileOptions & options,FileResourceCallback callback,ProgressCallback progress_callback)193 BatchRequestConfigurator::MultipartUploadExistingFile(
194     const std::string& content_type,
195     int64_t content_length,
196     const std::string& resource_id,
197     const base::FilePath& local_file_path,
198     const UploadExistingFileOptions& options,
199     FileResourceCallback callback,
200     ProgressCallback progress_callback) {
201   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
202   DCHECK(!callback.is_null());
203 
204   std::unique_ptr<google_apis::BatchableDelegate> delegate(
205       new google_apis::drive::MultipartUploadExistingFileDelegate(
206           task_runner_.get(), options.title, resource_id,
207           options.parent_resource_id, content_type, content_length,
208           options.modified_date, options.last_viewed_by_me_date,
209           local_file_path, options.etag, options.properties, url_generator_,
210           std::move(callback), progress_callback));
211   // Batch request can be null when pre-authorization for the requst is failed
212   // in request sender.
213   if (batch_request_)
214     batch_request_->AddRequest(delegate.release());
215   else
216     delegate->NotifyError(DRIVE_OTHER_ERROR);
217   return cancel_callback_;
218 }
219 
Commit()220 void BatchRequestConfigurator::Commit() {
221   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
222   if (!batch_request_)
223     return;
224   batch_request_->Commit();
225   batch_request_.reset();
226 }
227 
DriveAPIService(signin::IdentityManager * identity_manager,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,base::SequencedTaskRunner * blocking_task_runner,const GURL & base_url,const GURL & base_thumbnail_url,const std::string & custom_user_agent,const net::NetworkTrafficAnnotationTag & traffic_annotation)228 DriveAPIService::DriveAPIService(
229     signin::IdentityManager* identity_manager,
230     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
231     base::SequencedTaskRunner* blocking_task_runner,
232     const GURL& base_url,
233     const GURL& base_thumbnail_url,
234     const std::string& custom_user_agent,
235     const net::NetworkTrafficAnnotationTag& traffic_annotation)
236     : identity_manager_(identity_manager),
237       url_loader_factory_(url_loader_factory),
238       blocking_task_runner_(blocking_task_runner),
239       url_generator_(base_url, base_thumbnail_url),
240       custom_user_agent_(custom_user_agent),
241       traffic_annotation_(traffic_annotation) {}
242 
~DriveAPIService()243 DriveAPIService::~DriveAPIService() {
244   DCHECK(thread_checker_.CalledOnValidThread());
245   if (sender_)
246     sender_->auth_service()->RemoveObserver(this);
247 }
248 
Initialize(const CoreAccountId & account_id)249 void DriveAPIService::Initialize(const CoreAccountId& account_id) {
250   DCHECK(thread_checker_.CalledOnValidThread());
251 
252   std::vector<std::string> scopes;
253   scopes.push_back(kDriveScope);
254   scopes.push_back(kDriveAppsReadonlyScope);
255   scopes.push_back(kDriveAppsScope);
256 
257   sender_ = std::make_unique<RequestSender>(
258       std::make_unique<google_apis::AuthService>(identity_manager_, account_id,
259                                                  url_loader_factory_, scopes),
260       url_loader_factory_, blocking_task_runner_.get(), custom_user_agent_,
261       traffic_annotation_);
262   sender_->auth_service()->AddObserver(this);
263 
264   files_list_request_runner_ =
265       std::make_unique<FilesListRequestRunner>(sender_.get(), url_generator_);
266 }
267 
AddObserver(DriveServiceObserver * observer)268 void DriveAPIService::AddObserver(DriveServiceObserver* observer) {
269   observers_.AddObserver(observer);
270 }
271 
RemoveObserver(DriveServiceObserver * observer)272 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) {
273   observers_.RemoveObserver(observer);
274 }
275 
CanSendRequest() const276 bool DriveAPIService::CanSendRequest() const {
277   DCHECK(thread_checker_.CalledOnValidThread());
278 
279   return HasRefreshToken();
280 }
281 
GetRootResourceId() const282 std::string DriveAPIService::GetRootResourceId() const {
283   return kDriveApiRootDirectoryResourceId;
284 }
285 
GetAllTeamDriveList(TeamDriveListCallback callback)286 CancelCallbackOnce DriveAPIService::GetAllTeamDriveList(
287     TeamDriveListCallback callback) {
288   DCHECK(thread_checker_.CalledOnValidThread());
289   DCHECK(callback);
290 
291   std::unique_ptr<TeamDriveListRequest> request =
292       std::make_unique<TeamDriveListRequest>(sender_.get(), url_generator_,
293                                              std::move(callback));
294   request->set_max_results(kMaxNumTeamDriveResourcePerRequest);
295   request->set_fields(kTeamDrivesListFields);
296   return sender_->StartRequestWithAuthRetry(std::move(request));
297 }
298 
GetAllFileList(const std::string & team_drive_id,FileListCallback callback)299 CancelCallbackOnce DriveAPIService::GetAllFileList(
300     const std::string& team_drive_id,
301     FileListCallback callback) {
302   DCHECK(thread_checker_.CalledOnValidThread());
303   DCHECK(!callback.is_null());
304 
305   std::unique_ptr<FilesListRequest> request =
306       std::make_unique<FilesListRequest>(sender_.get(), url_generator_,
307                                          std::move(callback));
308   request->set_max_results(kMaxNumFilesResourcePerRequest);
309   request->set_q("trashed = false");  // Exclude trashed files.
310   request->set_fields(kFileListFields);
311   if (team_drive_id.empty()) {
312     request->set_corpora(google_apis::FilesListCorpora::DEFAULT);
313   } else {
314     request->set_team_drive_id(team_drive_id);
315     request->set_corpora(google_apis::FilesListCorpora::TEAM_DRIVE);
316   }
317   return sender_->StartRequestWithAuthRetry(std::move(request));
318 }
319 
GetFileListInDirectory(const std::string & directory_resource_id,FileListCallback callback)320 CancelCallbackOnce DriveAPIService::GetFileListInDirectory(
321     const std::string& directory_resource_id,
322     FileListCallback callback) {
323   DCHECK(thread_checker_.CalledOnValidThread());
324   DCHECK(!directory_resource_id.empty());
325   DCHECK(!callback.is_null());
326 
327   // TODO(yamaguchi): Use FileListScope::CreateForTeamDrive instead of
328   // kAllTeamDrives for efficiency. It'll require to add a new parameter to tell
329   // which team drive the directory resource belongs to.
330   FilesListCorpora corpora = google_apis::FilesListCorpora::ALL_TEAM_DRIVES;
331 
332   // Because children.list method on Drive API v2 returns only the list of
333   // children's references, but we need all file resource list.
334   // So, here we use files.list method instead, with setting parents query.
335   // After the migration from GData WAPI to Drive API v2, we should clean the
336   // code up by moving the responsibility to include "parents" in the query
337   // to client side.
338   // We aren't interested in files in trash in this context, neither.
339   return files_list_request_runner_->CreateAndStartWithSizeBackoff(
340       kMaxNumFilesResourcePerRequest, corpora, std::string(),
341       base::StringPrintf(
342           "'%s' in parents and trashed = false",
343           util::EscapeQueryStringValue(directory_resource_id).c_str()),
344       kFileListFields, std::move(callback));
345 }
346 
Search(const std::string & search_query,FileListCallback callback)347 CancelCallback DriveAPIService::Search(const std::string& search_query,
348                                        FileListCallback callback) {
349   DCHECK(thread_checker_.CalledOnValidThread());
350   DCHECK(!search_query.empty());
351   DCHECK(!callback.is_null());
352 
353   FilesListCorpora corpora = google_apis::FilesListCorpora::ALL_TEAM_DRIVES;
354 
355   std::string query = util::TranslateQuery(search_query);
356   if (!query.empty())
357     query += " and ";
358   query += "trashed = false";
359 
360   return files_list_request_runner_->CreateAndStartWithSizeBackoff(
361       kMaxNumFilesResourcePerRequestForSearch, corpora, std::string(), query,
362       kFileListFields, std::move(callback));
363 }
364 
SearchByTitle(const std::string & title,const std::string & directory_resource_id,FileListCallback callback)365 CancelCallbackOnce DriveAPIService::SearchByTitle(
366     const std::string& title,
367     const std::string& directory_resource_id,
368     FileListCallback callback) {
369   DCHECK(thread_checker_.CalledOnValidThread());
370   DCHECK(!title.empty());
371   DCHECK(!callback.is_null());
372 
373   std::string query;
374   base::StringAppendF(&query, "title = '%s'",
375                       util::EscapeQueryStringValue(title).c_str());
376   if (!directory_resource_id.empty()) {
377     base::StringAppendF(
378         &query, " and '%s' in parents",
379         util::EscapeQueryStringValue(directory_resource_id).c_str());
380   }
381   query += " and trashed = false";
382 
383   std::unique_ptr<FilesListRequest> request =
384       std::make_unique<FilesListRequest>(sender_.get(), url_generator_,
385                                          std::move(callback));
386   request->set_max_results(kMaxNumFilesResourcePerRequest);
387   request->set_q(query);
388   request->set_fields(kFileListFields);
389   return sender_->StartRequestWithAuthRetry(std::move(request));
390 }
391 
GetChangeList(int64_t start_changestamp,ChangeListCallback callback)392 CancelCallback DriveAPIService::GetChangeList(int64_t start_changestamp,
393                                               ChangeListCallback callback) {
394   DCHECK(thread_checker_.CalledOnValidThread());
395   DCHECK(callback);
396 
397   std::unique_ptr<ChangesListRequest> request =
398       std::make_unique<ChangesListRequest>(sender_.get(), url_generator_,
399                                            std::move(callback));
400   request->set_max_results(kMaxNumFilesResourcePerRequest);
401   request->set_start_change_id(start_changestamp);
402   request->set_fields(kChangeListFields);
403   return sender_->StartRequestWithAuthRetry(std::move(request));
404 }
405 
GetChangeListByToken(const std::string & team_drive_id,const std::string & start_page_token,ChangeListCallback callback)406 CancelCallback DriveAPIService::GetChangeListByToken(
407     const std::string& team_drive_id,
408     const std::string& start_page_token,
409     ChangeListCallback callback) {
410   DCHECK(thread_checker_.CalledOnValidThread());
411   DCHECK(callback);
412 
413   std::unique_ptr<ChangesListRequest> request =
414       std::make_unique<ChangesListRequest>(sender_.get(), url_generator_,
415                                            std::move(callback));
416   request->set_max_results(kMaxNumFilesResourcePerRequest);
417   request->set_page_token(start_page_token);
418   request->set_team_drive_id(team_drive_id);
419   request->set_fields(kChangeListFields);
420   return sender_->StartRequestWithAuthRetry(std::move(request));
421 }
422 
GetRemainingChangeList(const GURL & next_link,ChangeListCallback callback)423 CancelCallbackOnce DriveAPIService::GetRemainingChangeList(
424     const GURL& next_link,
425     ChangeListCallback callback) {
426   DCHECK(thread_checker_.CalledOnValidThread());
427   DCHECK(!next_link.is_empty());
428   DCHECK(callback);
429 
430   std::unique_ptr<ChangesListNextPageRequest> request =
431       std::make_unique<ChangesListNextPageRequest>(sender_.get(),
432                                                    std::move(callback));
433   request->set_next_link(next_link);
434   request->set_fields(kChangeListFields);
435   return sender_->StartRequestWithAuthRetry(std::move(request));
436 }
437 
GetRemainingTeamDriveList(const std::string & page_token,TeamDriveListCallback callback)438 CancelCallback DriveAPIService::GetRemainingTeamDriveList(
439     const std::string& page_token,
440     TeamDriveListCallback callback) {
441   DCHECK(thread_checker_.CalledOnValidThread());
442   DCHECK(!page_token.empty());
443   DCHECK(callback);
444 
445   std::unique_ptr<TeamDriveListRequest> request =
446       std::make_unique<TeamDriveListRequest>(sender_.get(), url_generator_,
447                                              std::move(callback));
448   request->set_page_token(page_token);
449   request->set_max_results(kMaxNumTeamDriveResourcePerRequest);
450   request->set_fields(kTeamDrivesListFields);
451   return sender_->StartRequestWithAuthRetry(std::move(request));
452 }
453 
GetRemainingFileList(const GURL & next_link,FileListCallback callback)454 CancelCallbackOnce DriveAPIService::GetRemainingFileList(
455     const GURL& next_link,
456     FileListCallback callback) {
457   DCHECK(thread_checker_.CalledOnValidThread());
458   DCHECK(!next_link.is_empty());
459   DCHECK(!callback.is_null());
460 
461   std::unique_ptr<FilesListNextPageRequest> request =
462       std::make_unique<FilesListNextPageRequest>(sender_.get(),
463                                                  std::move(callback));
464   request->set_next_link(next_link);
465   request->set_fields(kFileListFields);
466   return sender_->StartRequestWithAuthRetry(std::move(request));
467 }
468 
GetFileResource(const std::string & resource_id,FileResourceCallback callback)469 CancelCallback DriveAPIService::GetFileResource(const std::string& resource_id,
470                                                 FileResourceCallback callback) {
471   DCHECK(thread_checker_.CalledOnValidThread());
472   DCHECK(!callback.is_null());
473 
474   std::unique_ptr<FilesGetRequest> request = std::make_unique<FilesGetRequest>(
475       sender_.get(), url_generator_, std::move(callback));
476   request->set_file_id(resource_id);
477   request->set_fields(kFileResourceFields);
478   return sender_->StartRequestWithAuthRetry(std::move(request));
479 }
480 
GetAboutResource(AboutResourceCallback callback)481 CancelCallback DriveAPIService::GetAboutResource(
482     AboutResourceCallback callback) {
483   DCHECK(thread_checker_.CalledOnValidThread());
484   DCHECK(callback);
485 
486   std::unique_ptr<AboutGetRequest> request = std::make_unique<AboutGetRequest>(
487       sender_.get(), url_generator_, std::move(callback));
488   request->set_fields(kAboutResourceFields);
489   return sender_->StartRequestWithAuthRetry(std::move(request));
490 }
491 
GetStartPageToken(const std::string & team_drive_id,StartPageTokenCallback callback)492 CancelCallback DriveAPIService::GetStartPageToken(
493     const std::string& team_drive_id,
494     StartPageTokenCallback callback) {
495   DCHECK(thread_checker_.CalledOnValidThread());
496   DCHECK(!callback.is_null());
497 
498   std::unique_ptr<StartPageTokenRequest> request =
499       std::make_unique<StartPageTokenRequest>(sender_.get(), url_generator_,
500                                               std::move(callback));
501   request->set_team_drive_id(team_drive_id);
502   return sender_->StartRequestWithAuthRetry(std::move(request));
503 }
504 
DownloadFile(const base::FilePath & local_cache_path,const std::string & resource_id,const DownloadActionCallback & download_action_callback,const GetContentCallback & get_content_callback,ProgressCallback progress_callback)505 CancelCallbackOnce DriveAPIService::DownloadFile(
506     const base::FilePath& local_cache_path,
507     const std::string& resource_id,
508     const DownloadActionCallback& download_action_callback,
509     const GetContentCallback& get_content_callback,
510     ProgressCallback progress_callback) {
511   DCHECK(thread_checker_.CalledOnValidThread());
512   DCHECK(!download_action_callback.is_null());
513   // get_content_callback may be null.
514 
515   return sender_->StartRequestWithAuthRetry(
516       std::make_unique<DownloadFileRequest>(
517           sender_.get(), url_generator_, resource_id, local_cache_path,
518           download_action_callback, get_content_callback, progress_callback));
519 }
520 
DeleteResource(const std::string & resource_id,const std::string & etag,EntryActionCallback callback)521 CancelCallback DriveAPIService::DeleteResource(const std::string& resource_id,
522                                                const std::string& etag,
523                                                EntryActionCallback callback) {
524   DCHECK(thread_checker_.CalledOnValidThread());
525   DCHECK(callback);
526 
527   std::unique_ptr<FilesDeleteRequest> request =
528       std::make_unique<FilesDeleteRequest>(sender_.get(), url_generator_,
529                                            std::move(callback));
530   request->set_file_id(resource_id);
531   request->set_etag(etag);
532   return sender_->StartRequestWithAuthRetry(std::move(request));
533 }
534 
TrashResource(const std::string & resource_id,EntryActionCallback callback)535 CancelCallback DriveAPIService::TrashResource(const std::string& resource_id,
536                                               EntryActionCallback callback) {
537   DCHECK(thread_checker_.CalledOnValidThread());
538   DCHECK(callback);
539 
540   std::unique_ptr<FilesTrashRequest> request =
541       std::make_unique<FilesTrashRequest>(
542           sender_.get(), url_generator_,
543           base::BindOnce(&EntryActionCallbackAdapter, std::move(callback)));
544   request->set_file_id(resource_id);
545   request->set_fields(kFileResourceFields);
546   return sender_->StartRequestWithAuthRetry(std::move(request));
547 }
548 
AddNewDirectory(const std::string & parent_resource_id,const std::string & directory_title,const AddNewDirectoryOptions & options,FileResourceCallback callback)549 CancelCallbackOnce DriveAPIService::AddNewDirectory(
550     const std::string& parent_resource_id,
551     const std::string& directory_title,
552     const AddNewDirectoryOptions& options,
553     FileResourceCallback callback) {
554   DCHECK(thread_checker_.CalledOnValidThread());
555   DCHECK(!callback.is_null());
556 
557   std::unique_ptr<FilesInsertRequest> request =
558       std::make_unique<FilesInsertRequest>(sender_.get(), url_generator_,
559                                            std::move(callback));
560   request->set_visibility(options.visibility);
561   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
562   request->set_mime_type(kFolderMimeType);
563   request->set_modified_date(options.modified_date);
564   request->add_parent(parent_resource_id);
565   request->set_title(directory_title);
566   request->set_properties(options.properties);
567   request->set_fields(kFileResourceFields);
568   return sender_->StartRequestWithAuthRetry(std::move(request));
569 }
570 
CopyResource(const std::string & resource_id,const std::string & parent_resource_id,const std::string & new_title,const base::Time & last_modified,FileResourceCallback callback)571 CancelCallback DriveAPIService::CopyResource(
572     const std::string& resource_id,
573     const std::string& parent_resource_id,
574     const std::string& new_title,
575     const base::Time& last_modified,
576     FileResourceCallback callback) {
577   DCHECK(thread_checker_.CalledOnValidThread());
578   DCHECK(!callback.is_null());
579 
580   std::unique_ptr<FilesCopyRequest> request =
581       std::make_unique<FilesCopyRequest>(sender_.get(), url_generator_,
582                                          std::move(callback));
583   request->set_file_id(resource_id);
584   request->add_parent(parent_resource_id);
585   request->set_title(new_title);
586   request->set_modified_date(last_modified);
587   request->set_fields(kFileResourceFields);
588   return sender_->StartRequestWithAuthRetry(std::move(request));
589 }
590 
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::drive::Properties & properties,FileResourceCallback callback)591 CancelCallback DriveAPIService::UpdateResource(
592     const std::string& resource_id,
593     const std::string& parent_resource_id,
594     const std::string& new_title,
595     const base::Time& last_modified,
596     const base::Time& last_viewed_by_me,
597     const google_apis::drive::Properties& properties,
598     FileResourceCallback callback) {
599   DCHECK(thread_checker_.CalledOnValidThread());
600   DCHECK(!callback.is_null());
601 
602   std::unique_ptr<FilesPatchRequest> request =
603       std::make_unique<FilesPatchRequest>(sender_.get(), url_generator_,
604                                           std::move(callback));
605   request->set_file_id(resource_id);
606   request->set_title(new_title);
607   if (!parent_resource_id.empty())
608     request->add_parent(parent_resource_id);
609   if (!last_modified.is_null()) {
610     // Need to set setModifiedDate to true to overwrite modifiedDate.
611     request->set_set_modified_date(true);
612     request->set_modified_date(last_modified);
613   }
614   if (!last_viewed_by_me.is_null()) {
615     // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
616     // will be set to the request time (not the specified time via request).
617     request->set_update_viewed_date(false);
618     request->set_last_viewed_by_me_date(last_viewed_by_me);
619   }
620   request->set_fields(kFileResourceFields);
621   request->set_properties(properties);
622   return sender_->StartRequestWithAuthRetry(std::move(request));
623 }
624 
AddResourceToDirectory(const std::string & parent_resource_id,const std::string & resource_id,EntryActionCallback callback)625 CancelCallback DriveAPIService::AddResourceToDirectory(
626     const std::string& parent_resource_id,
627     const std::string& resource_id,
628     EntryActionCallback callback) {
629   DCHECK(thread_checker_.CalledOnValidThread());
630   DCHECK(callback);
631 
632   std::unique_ptr<ChildrenInsertRequest> request =
633       std::make_unique<ChildrenInsertRequest>(sender_.get(), url_generator_,
634                                               std::move(callback));
635   request->set_folder_id(parent_resource_id);
636   request->set_id(resource_id);
637   return sender_->StartRequestWithAuthRetry(std::move(request));
638 }
639 
RemoveResourceFromDirectory(const std::string & parent_resource_id,const std::string & resource_id,EntryActionCallback callback)640 CancelCallbackOnce DriveAPIService::RemoveResourceFromDirectory(
641     const std::string& parent_resource_id,
642     const std::string& resource_id,
643     EntryActionCallback callback) {
644   DCHECK(thread_checker_.CalledOnValidThread());
645   DCHECK(callback);
646 
647   std::unique_ptr<ChildrenDeleteRequest> request =
648       std::make_unique<ChildrenDeleteRequest>(sender_.get(), url_generator_,
649                                               std::move(callback));
650   request->set_child_id(resource_id);
651   request->set_folder_id(parent_resource_id);
652   return sender_->StartRequestWithAuthRetry(std::move(request));
653 }
654 
InitiateUploadNewFile(const std::string & content_type,int64_t content_length,const std::string & parent_resource_id,const std::string & title,const UploadNewFileOptions & options,const InitiateUploadCallback & callback)655 CancelCallback DriveAPIService::InitiateUploadNewFile(
656     const std::string& content_type,
657     int64_t content_length,
658     const std::string& parent_resource_id,
659     const std::string& title,
660     const UploadNewFileOptions& options,
661     const InitiateUploadCallback& callback) {
662   DCHECK(thread_checker_.CalledOnValidThread());
663   DCHECK(!callback.is_null());
664 
665   std::unique_ptr<InitiateUploadNewFileRequest> request =
666       std::make_unique<InitiateUploadNewFileRequest>(
667           sender_.get(), url_generator_, content_type, content_length,
668           parent_resource_id, title, callback);
669   request->set_modified_date(options.modified_date);
670   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
671   request->set_properties(options.properties);
672   return sender_->StartRequestWithAuthRetry(std::move(request));
673 }
674 
InitiateUploadExistingFile(const std::string & content_type,int64_t content_length,const std::string & resource_id,const UploadExistingFileOptions & options,const InitiateUploadCallback & callback)675 CancelCallback DriveAPIService::InitiateUploadExistingFile(
676     const std::string& content_type,
677     int64_t content_length,
678     const std::string& resource_id,
679     const UploadExistingFileOptions& options,
680     const InitiateUploadCallback& callback) {
681   DCHECK(thread_checker_.CalledOnValidThread());
682   DCHECK(!callback.is_null());
683 
684   std::unique_ptr<InitiateUploadExistingFileRequest> request =
685       std::make_unique<InitiateUploadExistingFileRequest>(
686           sender_.get(), url_generator_, content_type, content_length,
687           resource_id, options.etag, callback);
688   request->set_parent_resource_id(options.parent_resource_id);
689   request->set_title(options.title);
690   request->set_modified_date(options.modified_date);
691   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
692   request->set_properties(options.properties);
693   return sender_->StartRequestWithAuthRetry(std::move(request));
694 }
695 
ResumeUpload(const GURL & upload_url,int64_t start_position,int64_t end_position,int64_t content_length,const std::string & content_type,const base::FilePath & local_file_path,UploadRangeCallback callback,ProgressCallback progress_callback)696 CancelCallback DriveAPIService::ResumeUpload(
697     const GURL& upload_url,
698     int64_t start_position,
699     int64_t end_position,
700     int64_t content_length,
701     const std::string& content_type,
702     const base::FilePath& local_file_path,
703     UploadRangeCallback callback,
704     ProgressCallback progress_callback) {
705   DCHECK(thread_checker_.CalledOnValidThread());
706   DCHECK(!callback.is_null());
707 
708   return sender_->StartRequestWithAuthRetry(
709       std::make_unique<ResumeUploadRequest>(
710           sender_.get(), upload_url, start_position, end_position,
711           content_length, content_type, local_file_path, std::move(callback),
712           progress_callback));
713 }
714 
GetUploadStatus(const GURL & upload_url,int64_t content_length,UploadRangeCallback callback)715 CancelCallback DriveAPIService::GetUploadStatus(const GURL& upload_url,
716                                                 int64_t content_length,
717                                                 UploadRangeCallback callback) {
718   DCHECK(thread_checker_.CalledOnValidThread());
719   DCHECK(!callback.is_null());
720 
721   return sender_->StartRequestWithAuthRetry(
722       std::make_unique<GetUploadStatusRequest>(
723           sender_.get(), upload_url, content_length, std::move(callback)));
724 }
725 
MultipartUploadNewFile(const std::string & content_type,int64_t content_length,const std::string & parent_resource_id,const std::string & title,const base::FilePath & local_file_path,const drive::UploadNewFileOptions & options,FileResourceCallback callback,ProgressCallback progress_callback)726 CancelCallbackRepeating DriveAPIService::MultipartUploadNewFile(
727     const std::string& content_type,
728     int64_t content_length,
729     const std::string& parent_resource_id,
730     const std::string& title,
731     const base::FilePath& local_file_path,
732     const drive::UploadNewFileOptions& options,
733     FileResourceCallback callback,
734     ProgressCallback progress_callback) {
735   DCHECK(thread_checker_.CalledOnValidThread());
736   DCHECK(!callback.is_null());
737 
738   return sender_->StartRequestWithAuthRetry(
739       std::make_unique<google_apis::drive::SingleBatchableDelegateRequest>(
740           sender_.get(),
741           std::make_unique<google_apis::drive::MultipartUploadNewFileDelegate>(
742               sender_->blocking_task_runner(), title, parent_resource_id,
743               content_type, content_length, options.modified_date,
744               options.last_viewed_by_me_date, local_file_path,
745               options.properties, url_generator_, std::move(callback),
746               progress_callback)));
747 }
748 
MultipartUploadExistingFile(const std::string & content_type,int64_t content_length,const std::string & resource_id,const base::FilePath & local_file_path,const drive::UploadExistingFileOptions & options,FileResourceCallback callback,ProgressCallback progress_callback)749 CancelCallbackRepeating DriveAPIService::MultipartUploadExistingFile(
750     const std::string& content_type,
751     int64_t content_length,
752     const std::string& resource_id,
753     const base::FilePath& local_file_path,
754     const drive::UploadExistingFileOptions& options,
755     FileResourceCallback callback,
756     ProgressCallback progress_callback) {
757   DCHECK(thread_checker_.CalledOnValidThread());
758   DCHECK(!callback.is_null());
759 
760   return sender_->StartRequestWithAuthRetry(
761       std::make_unique<google_apis::drive::SingleBatchableDelegateRequest>(
762           sender_.get(),
763           std::make_unique<
764               google_apis::drive::MultipartUploadExistingFileDelegate>(
765               sender_->blocking_task_runner(), options.title, resource_id,
766               options.parent_resource_id, content_type, content_length,
767               options.modified_date, options.last_viewed_by_me_date,
768               local_file_path, options.etag, options.properties, url_generator_,
769               std::move(callback), progress_callback)));
770 }
771 
AddPermission(const std::string & resource_id,const std::string & email,google_apis::drive::PermissionRole role,google_apis::EntryActionCallback callback)772 google_apis::CancelCallback DriveAPIService::AddPermission(
773     const std::string& resource_id,
774     const std::string& email,
775     google_apis::drive::PermissionRole role,
776     google_apis::EntryActionCallback callback) {
777   DCHECK(thread_checker_.CalledOnValidThread());
778   DCHECK(callback);
779 
780   std::unique_ptr<google_apis::drive::PermissionsInsertRequest> request =
781       std::make_unique<google_apis::drive::PermissionsInsertRequest>(
782           sender_.get(), url_generator_, std::move(callback));
783   request->set_id(resource_id);
784   request->set_role(role);
785   request->set_type(google_apis::drive::PERMISSION_TYPE_USER);
786   request->set_value(email);
787   return sender_->StartRequestWithAuthRetry(std::move(request));
788 }
789 
HasAccessToken() const790 bool DriveAPIService::HasAccessToken() const {
791   DCHECK(thread_checker_.CalledOnValidThread());
792   return sender_->auth_service()->HasAccessToken();
793 }
794 
RequestAccessToken(AuthStatusCallback callback)795 void DriveAPIService::RequestAccessToken(AuthStatusCallback callback) {
796   DCHECK(thread_checker_.CalledOnValidThread());
797   DCHECK(callback);
798 
799   const std::string access_token = sender_->auth_service()->access_token();
800   if (!access_token.empty()) {
801     std::move(callback).Run(google_apis::HTTP_NOT_MODIFIED, access_token);
802     return;
803   }
804 
805   // Retrieve the new auth token.
806   sender_->auth_service()->StartAuthentication(std::move(callback));
807 }
808 
HasRefreshToken() const809 bool DriveAPIService::HasRefreshToken() const {
810   DCHECK(thread_checker_.CalledOnValidThread());
811   return sender_->auth_service()->HasRefreshToken();
812 }
813 
ClearAccessToken()814 void DriveAPIService::ClearAccessToken() {
815   DCHECK(thread_checker_.CalledOnValidThread());
816   sender_->auth_service()->ClearAccessToken();
817 }
818 
ClearRefreshToken()819 void DriveAPIService::ClearRefreshToken() {
820   DCHECK(thread_checker_.CalledOnValidThread());
821   sender_->auth_service()->ClearRefreshToken();
822 }
823 
OnOAuth2RefreshTokenChanged()824 void DriveAPIService::OnOAuth2RefreshTokenChanged() {
825   DCHECK(thread_checker_.CalledOnValidThread());
826   if (CanSendRequest()) {
827     for (auto& observer : observers_)
828       observer.OnReadyToSendRequests();
829   } else if (!HasRefreshToken()) {
830     for (auto& observer : observers_)
831       observer.OnRefreshTokenInvalid();
832   }
833 }
834 
835 std::unique_ptr<BatchRequestConfiguratorInterface>
StartBatchRequest()836 DriveAPIService::StartBatchRequest() {
837   std::unique_ptr<google_apis::drive::BatchUploadRequest> request =
838       std::make_unique<google_apis::drive::BatchUploadRequest>(sender_.get(),
839                                                                url_generator_);
840   const base::WeakPtr<google_apis::drive::BatchUploadRequest> weak_ref =
841       request->GetWeakPtrAsBatchUploadRequest();
842   // Have sender_ manage the lifetime of the request.
843   // TODO(hirono): Currently we need to pass the ownership of the request to
844   // RequestSender before the request is committed because the request has a
845   // reference to RequestSender and we should ensure to delete the request when
846   // the sender is deleted. Resolve the circulating dependency and fix it.
847   const google_apis::CancelCallback callback =
848       sender_->StartRequestWithAuthRetry(std::move(request));
849   return std::make_unique<BatchRequestConfigurator>(
850       weak_ref, sender_->blocking_task_runner(), url_generator_, callback);
851 }
852 
853 }  // namespace drive
854