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