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.
5 #include "chrome/browser/drive/drive_api_service.h"
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"
27 using content::BrowserThread
;
28 using google_apis::AppList
;
29 using google_apis::AppListCallback
;
30 using google_apis::AuthStatusCallback
;
31 using google_apis::AuthorizeAppCallback
;
32 using google_apis::CancelCallback
;
33 using google_apis::ChangeList
;
34 using google_apis::DownloadActionCallback
;
35 using google_apis::EntryActionCallback
;
36 using google_apis::FileList
;
37 using google_apis::FileResource
;
38 using google_apis::GDATA_OTHER_ERROR
;
39 using google_apis::GDATA_PARSE_ERROR
;
40 using google_apis::GDataErrorCode
;
41 using google_apis::AboutResourceCallback
;
42 using google_apis::GetContentCallback
;
43 using google_apis::GetResourceEntryCallback
;
44 using google_apis::GetResourceEntryRequest
;
45 using google_apis::GetResourceListCallback
;
46 using google_apis::GetResourceListRequest
;
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::ResourceEntry
;
55 using google_apis::ResourceList
;
56 using google_apis::UploadRangeCallback
;
57 using google_apis::UploadRangeResponse
;
58 using google_apis::drive::AboutGetRequest
;
59 using google_apis::drive::AppsListRequest
;
60 using google_apis::drive::ChangesListRequest
;
61 using google_apis::drive::ChangesListNextPageRequest
;
62 using google_apis::drive::ChildrenDeleteRequest
;
63 using google_apis::drive::ChildrenInsertRequest
;
64 using google_apis::drive::DownloadFileRequest
;
65 using google_apis::drive::FilesCopyRequest
;
66 using google_apis::drive::FilesGetRequest
;
67 using google_apis::drive::FilesInsertRequest
;
68 using google_apis::drive::FilesPatchRequest
;
69 using google_apis::drive::FilesListRequest
;
70 using google_apis::drive::FilesListNextPageRequest
;
71 using google_apis::drive::FilesDeleteRequest
;
72 using google_apis::drive::FilesTrashRequest
;
73 using google_apis::drive::GetUploadStatusRequest
;
74 using google_apis::drive::InitiateUploadExistingFileRequest
;
75 using google_apis::drive::InitiateUploadNewFileRequest
;
76 using google_apis::drive::ResumeUploadRequest
;
82 // OAuth2 scopes for Drive API.
83 const char kDriveScope
[] = "https://www.googleapis.com/auth/drive";
84 const char kDriveAppsReadonlyScope
[] =
85 "https://www.googleapis.com/auth/drive.apps.readonly";
87 // Mime type to create a directory.
88 const char kFolderMimeType
[] = "application/vnd.google-apps.folder";
90 // Max number of file entries to be fetched in a single http request.
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
= 250;
100 const int kMaxNumFilesResourcePerRequestForSearch
= 50;
102 // For performance, we declare all fields we use.
103 const char kAboutResourceFields
[] =
104 "kind,quotaBytesTotal,quotaBytesUsed,largestChangeId,rootFolderId";
105 const char kFileResourceFields
[] =
106 "kind,id,title,createdDate,sharedWithMeDate,downloadUrl,mimeType,"
107 "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
108 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
109 "parents/parentLink,selfLink,thumbnailLink,alternateLink,embedLink,"
110 "modifiedDate,lastViewedByMeDate,shared";
111 const char kFileResourceOpenWithLinksFields
[] =
112 "kind,id,openWithLinks/*";
113 const char kFileListFields
[] =
114 "kind,items(kind,id,title,createdDate,sharedWithMeDate,downloadUrl,"
115 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
116 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
117 "parents/parentLink,selfLink,thumbnailLink,alternateLink,embedLink,"
118 "modifiedDate,lastViewedByMeDate,shared),nextLink";
119 const char kChangeListFields
[] =
120 "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,downloadUrl,"
121 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
122 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
123 "parents/parentLink,selfLink,thumbnailLink,alternateLink,embedLink,"
124 "modifiedDate,lastViewedByMeDate,shared),deleted,id,fileId),nextLink,"
127 // Callback invoked when the parsing of resource list is completed,
128 // regardless whether it is succeeded or not.
129 void DidConvertToResourceListOnBlockingPool(
130 const GetResourceListCallback
& callback
,
131 scoped_ptr
<ResourceList
> resource_list
) {
132 GDataErrorCode error
= resource_list
? HTTP_SUCCESS
: GDATA_PARSE_ERROR
;
133 callback
.Run(error
, resource_list
.Pass());
136 // Converts the FileResource value to ResourceEntry and runs |callback| on the
138 void ConvertFileEntryToResourceEntryAndRun(
139 const GetResourceEntryCallback
& callback
,
140 GDataErrorCode error
,
141 scoped_ptr
<FileResource
> value
) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
143 DCHECK(!callback
.is_null());
146 callback
.Run(error
, scoped_ptr
<ResourceEntry
>());
150 // Converting to ResourceEntry is cheap enough to do on UI thread.
151 scoped_ptr
<ResourceEntry
> entry
=
152 util::ConvertFileResourceToResourceEntry(*value
);
154 callback
.Run(GDATA_PARSE_ERROR
, scoped_ptr
<ResourceEntry
>());
158 callback
.Run(error
, entry
.Pass());
161 // Thin adapter of ConvertFileListToResourceList.
162 scoped_ptr
<ResourceList
> ConvertFileListToResourceList(
163 scoped_ptr
<FileList
> file_list
) {
164 return util::ConvertFileListToResourceList(*file_list
);
167 // Converts the FileList value to ResourceList on blocking pool and runs
168 // |callback| on the UI thread.
169 void ConvertFileListToResourceListOnBlockingPoolAndRun(
170 scoped_refptr
<base::TaskRunner
> blocking_task_runner
,
171 const GetResourceListCallback
& callback
,
172 GDataErrorCode error
,
173 scoped_ptr
<FileList
> value
) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
175 DCHECK(!callback
.is_null());
178 callback
.Run(error
, scoped_ptr
<ResourceList
>());
182 // Convert the value on blocking pool.
183 base::PostTaskAndReplyWithResult(
184 blocking_task_runner
.get(),
186 base::Bind(&ConvertFileListToResourceList
, base::Passed(&value
)),
187 base::Bind(&DidConvertToResourceListOnBlockingPool
, callback
));
190 // Thin adapter of ConvertChangeListToResourceList.
191 scoped_ptr
<ResourceList
> ConvertChangeListToResourceList(
192 scoped_ptr
<ChangeList
> change_list
) {
193 return util::ConvertChangeListToResourceList(*change_list
);
196 // Converts the FileList value to ResourceList on blocking pool and runs
197 // |callback| on the UI thread.
198 void ConvertChangeListToResourceListOnBlockingPoolAndRun(
199 scoped_refptr
<base::TaskRunner
> blocking_task_runner
,
200 const GetResourceListCallback
& callback
,
201 GDataErrorCode error
,
202 scoped_ptr
<ChangeList
> value
) {
203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
204 DCHECK(!callback
.is_null());
207 callback
.Run(error
, scoped_ptr
<ResourceList
>());
211 // Convert the value on blocking pool.
212 base::PostTaskAndReplyWithResult(
213 blocking_task_runner
.get(),
215 base::Bind(&ConvertChangeListToResourceList
, base::Passed(&value
)),
216 base::Bind(&DidConvertToResourceListOnBlockingPool
, callback
));
219 // Converts the FileResource value to ResourceEntry for upload range request,
220 // and runs |callback| on the UI thread.
221 void ConvertFileResourceToResourceEntryForUploadRangeAndRun(
222 const UploadRangeCallback
& callback
,
223 const UploadRangeResponse
& response
,
224 scoped_ptr
<FileResource
> value
) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
226 DCHECK(!callback
.is_null());
229 callback
.Run(response
, scoped_ptr
<ResourceEntry
>());
233 // Converting to ResourceEntry is cheap enough to do on UI thread.
234 scoped_ptr
<ResourceEntry
> entry
=
235 util::ConvertFileResourceToResourceEntry(*value
);
237 callback
.Run(UploadRangeResponse(GDATA_PARSE_ERROR
,
238 response
.start_position_received
,
239 response
.end_position_received
),
240 scoped_ptr
<ResourceEntry
>());
244 callback
.Run(response
, entry
.Pass());
247 void ExtractOpenUrlAndRun(const std::string
& app_id
,
248 const AuthorizeAppCallback
& callback
,
249 GDataErrorCode error
,
250 scoped_ptr
<FileResource
> value
) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
252 DCHECK(!callback
.is_null());
255 callback
.Run(error
, GURL());
259 const std::vector
<FileResource::OpenWithLink
>& open_with_links
=
260 value
->open_with_links();
261 for (size_t i
= 0; i
< open_with_links
.size(); ++i
) {
262 if (open_with_links
[i
].app_id
== app_id
) {
263 callback
.Run(HTTP_SUCCESS
, open_with_links
[i
].open_url
);
269 callback
.Run(GDATA_OTHER_ERROR
, GURL());
272 // Ignores the |entry|, and runs the |callback|.
273 void EntryActionCallbackAdapter(
274 const EntryActionCallback
& callback
,
275 GDataErrorCode error
, scoped_ptr
<FileResource
> entry
) {
279 // The resource ID for the root directory for Drive API is defined in the spec:
280 // https://developers.google.com/drive/folder
281 const char kDriveApiRootDirectoryResourceId
[] = "root";
285 DriveAPIService::DriveAPIService(
286 OAuth2TokenService
* oauth2_token_service
,
287 net::URLRequestContextGetter
* url_request_context_getter
,
288 base::SequencedTaskRunner
* blocking_task_runner
,
289 const GURL
& base_url
,
290 const GURL
& base_download_url
,
291 const GURL
& wapi_base_url
,
292 const std::string
& custom_user_agent
)
293 : oauth2_token_service_(oauth2_token_service
),
294 url_request_context_getter_(url_request_context_getter
),
295 blocking_task_runner_(blocking_task_runner
),
296 url_generator_(base_url
, base_download_url
),
297 wapi_url_generator_(wapi_base_url
, base_download_url
),
298 custom_user_agent_(custom_user_agent
) {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
302 DriveAPIService::~DriveAPIService() {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
305 sender_
->auth_service()->RemoveObserver(this);
308 void DriveAPIService::Initialize(const std::string
& account_id
) {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
311 std::vector
<std::string
> scopes
;
312 scopes
.push_back(kDriveScope
);
313 scopes
.push_back(kDriveAppsReadonlyScope
);
314 scopes
.push_back(util::kDriveAppsScope
);
316 // GData WAPI token for GetShareUrl() and GetResourceListInDirectoryByWapi().
317 scopes
.push_back(util::kDocsListScope
);
319 sender_
.reset(new RequestSender(
320 new google_apis::AuthService(oauth2_token_service_
,
322 url_request_context_getter_
.get(),
324 url_request_context_getter_
.get(),
325 blocking_task_runner_
.get(),
326 custom_user_agent_
));
327 sender_
->auth_service()->AddObserver(this);
330 void DriveAPIService::AddObserver(DriveServiceObserver
* observer
) {
331 observers_
.AddObserver(observer
);
334 void DriveAPIService::RemoveObserver(DriveServiceObserver
* observer
) {
335 observers_
.RemoveObserver(observer
);
338 bool DriveAPIService::CanSendRequest() const {
339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
341 return HasRefreshToken();
344 ResourceIdCanonicalizer
DriveAPIService::GetResourceIdCanonicalizer() const {
345 return base::Bind(&drive::util::CanonicalizeResourceId
);
348 std::string
DriveAPIService::GetRootResourceId() const {
349 return kDriveApiRootDirectoryResourceId
;
352 CancelCallback
DriveAPIService::GetAllResourceList(
353 const GetResourceListCallback
& callback
) {
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
355 DCHECK(!callback
.is_null());
357 FilesListRequest
* request
= new FilesListRequest(
358 sender_
.get(), url_generator_
,
359 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun
,
360 blocking_task_runner_
, callback
));
361 request
->set_max_results(kMaxNumFilesResourcePerRequest
);
362 request
->set_q("trashed = false"); // Exclude trashed files.
363 request
->set_fields(kFileListFields
);
364 return sender_
->StartRequestWithRetry(request
);
367 CancelCallback
DriveAPIService::GetResourceListInDirectory(
368 const std::string
& directory_resource_id
,
369 const GetResourceListCallback
& callback
) {
370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
371 DCHECK(!directory_resource_id
.empty());
372 DCHECK(!callback
.is_null());
374 // Because children.list method on Drive API v2 returns only the list of
375 // children's references, but we need all file resource list.
376 // So, here we use files.list method instead, with setting parents query.
377 // After the migration from GData WAPI to Drive API v2, we should clean the
378 // code up by moving the responsibility to include "parents" in the query
380 // We aren't interested in files in trash in this context, neither.
381 FilesListRequest
* request
= new FilesListRequest(
382 sender_
.get(), url_generator_
,
383 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun
,
384 blocking_task_runner_
, callback
));
385 request
->set_max_results(kMaxNumFilesResourcePerRequest
);
386 request
->set_q(base::StringPrintf(
387 "'%s' in parents and trashed = false",
388 drive::util::EscapeQueryStringValue(directory_resource_id
).c_str()));
389 request
->set_fields(kFileListFields
);
390 return sender_
->StartRequestWithRetry(request
);
393 CancelCallback
DriveAPIService::Search(
394 const std::string
& search_query
,
395 const GetResourceListCallback
& callback
) {
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
397 DCHECK(!search_query
.empty());
398 DCHECK(!callback
.is_null());
400 FilesListRequest
* request
= new FilesListRequest(
401 sender_
.get(), url_generator_
,
402 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun
,
403 blocking_task_runner_
, callback
));
404 request
->set_max_results(kMaxNumFilesResourcePerRequestForSearch
);
405 request
->set_q(drive::util::TranslateQuery(search_query
));
406 request
->set_fields(kFileListFields
);
407 return sender_
->StartRequestWithRetry(request
);
410 CancelCallback
DriveAPIService::SearchByTitle(
411 const std::string
& title
,
412 const std::string
& directory_resource_id
,
413 const GetResourceListCallback
& callback
) {
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
415 DCHECK(!title
.empty());
416 DCHECK(!callback
.is_null());
419 base::StringAppendF(&query
, "title = '%s'",
420 drive::util::EscapeQueryStringValue(title
).c_str());
421 if (!directory_resource_id
.empty()) {
423 &query
, " and '%s' in parents",
424 drive::util::EscapeQueryStringValue(directory_resource_id
).c_str());
426 query
+= " and trashed = false";
428 FilesListRequest
* request
= new FilesListRequest(
429 sender_
.get(), url_generator_
,
430 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun
,
431 blocking_task_runner_
, callback
));
432 request
->set_max_results(kMaxNumFilesResourcePerRequest
);
433 request
->set_q(query
);
434 request
->set_fields(kFileListFields
);
435 return sender_
->StartRequestWithRetry(request
);
438 CancelCallback
DriveAPIService::GetChangeList(
439 int64 start_changestamp
,
440 const GetResourceListCallback
& callback
) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
442 DCHECK(!callback
.is_null());
444 ChangesListRequest
* request
= new ChangesListRequest(
445 sender_
.get(), url_generator_
,
446 base::Bind(&ConvertChangeListToResourceListOnBlockingPoolAndRun
,
447 blocking_task_runner_
, callback
));
448 request
->set_max_results(kMaxNumFilesResourcePerRequest
);
449 request
->set_start_change_id(start_changestamp
);
450 request
->set_fields(kChangeListFields
);
451 return sender_
->StartRequestWithRetry(request
);
454 CancelCallback
DriveAPIService::GetRemainingChangeList(
455 const GURL
& next_link
,
456 const GetResourceListCallback
& callback
) {
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
458 DCHECK(!next_link
.is_empty());
459 DCHECK(!callback
.is_null());
461 ChangesListNextPageRequest
* request
= new ChangesListNextPageRequest(
463 base::Bind(&ConvertChangeListToResourceListOnBlockingPoolAndRun
,
464 blocking_task_runner_
, callback
));
465 request
->set_next_link(next_link
);
466 request
->set_fields(kChangeListFields
);
467 return sender_
->StartRequestWithRetry(request
);
470 CancelCallback
DriveAPIService::GetRemainingFileList(
471 const GURL
& next_link
,
472 const GetResourceListCallback
& callback
) {
473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
474 DCHECK(!next_link
.is_empty());
475 DCHECK(!callback
.is_null());
477 FilesListNextPageRequest
* request
= new FilesListNextPageRequest(
479 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun
,
480 blocking_task_runner_
, callback
));
481 request
->set_next_link(next_link
);
482 request
->set_fields(kFileListFields
);
483 return sender_
->StartRequestWithRetry(request
);
486 CancelCallback
DriveAPIService::GetResourceEntry(
487 const std::string
& resource_id
,
488 const GetResourceEntryCallback
& callback
) {
489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
490 DCHECK(!callback
.is_null());
492 FilesGetRequest
* request
= new FilesGetRequest(
493 sender_
.get(), url_generator_
,
494 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
495 request
->set_file_id(resource_id
);
496 request
->set_fields(kFileResourceFields
);
497 return sender_
->StartRequestWithRetry(request
);
500 CancelCallback
DriveAPIService::GetShareUrl(
501 const std::string
& resource_id
,
502 const GURL
& embed_origin
,
503 const GetShareUrlCallback
& callback
) {
504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
505 DCHECK(!callback
.is_null());
507 // Unfortunately "share url" is not yet supported on Drive API v2.
508 // So, as a fallback, we use GData WAPI protocol for this method.
509 // TODO(hidehiko): Get rid of this implementation when share url is
510 // supported on Drive API v2.
511 return sender_
->StartRequestWithRetry(
512 new GetResourceEntryRequest(sender_
.get(),
516 base::Bind(&util::ParseShareUrlAndRun
,
520 CancelCallback
DriveAPIService::GetAboutResource(
521 const AboutResourceCallback
& callback
) {
522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
523 DCHECK(!callback
.is_null());
525 AboutGetRequest
* request
=
526 new AboutGetRequest(sender_
.get(), url_generator_
, callback
);
527 request
->set_fields(kAboutResourceFields
);
528 return sender_
->StartRequestWithRetry(request
);
531 CancelCallback
DriveAPIService::GetAppList(const AppListCallback
& callback
) {
532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
533 DCHECK(!callback
.is_null());
535 return sender_
->StartRequestWithRetry(
536 new AppsListRequest(sender_
.get(), url_generator_
,
537 google_apis::IsGoogleChromeAPIKeyUsed(),
541 CancelCallback
DriveAPIService::DownloadFile(
542 const base::FilePath
& local_cache_path
,
543 const std::string
& resource_id
,
544 const DownloadActionCallback
& download_action_callback
,
545 const GetContentCallback
& get_content_callback
,
546 const ProgressCallback
& progress_callback
) {
547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
548 DCHECK(!download_action_callback
.is_null());
549 // get_content_callback may be null.
551 return sender_
->StartRequestWithRetry(
552 new DownloadFileRequest(sender_
.get(),
556 download_action_callback
,
557 get_content_callback
,
561 CancelCallback
DriveAPIService::DeleteResource(
562 const std::string
& resource_id
,
563 const std::string
& etag
,
564 const EntryActionCallback
& callback
) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
566 DCHECK(!callback
.is_null());
568 FilesDeleteRequest
* request
= new FilesDeleteRequest(
569 sender_
.get(), url_generator_
, callback
);
570 request
->set_file_id(resource_id
);
571 request
->set_etag(etag
);
572 return sender_
->StartRequestWithRetry(request
);
575 CancelCallback
DriveAPIService::TrashResource(
576 const std::string
& resource_id
,
577 const EntryActionCallback
& callback
) {
578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
579 DCHECK(!callback
.is_null());
581 FilesTrashRequest
* request
= new FilesTrashRequest(
582 sender_
.get(), url_generator_
,
583 base::Bind(&EntryActionCallbackAdapter
, callback
));
584 request
->set_file_id(resource_id
);
585 request
->set_fields(kFileResourceFields
);
586 return sender_
->StartRequestWithRetry(request
);
589 CancelCallback
DriveAPIService::AddNewDirectory(
590 const std::string
& parent_resource_id
,
591 const std::string
& directory_title
,
592 const AddNewDirectoryOptions
& options
,
593 const GetResourceEntryCallback
& callback
) {
594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
595 DCHECK(!callback
.is_null());
597 FilesInsertRequest
* request
= new FilesInsertRequest(
598 sender_
.get(), url_generator_
,
599 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
600 request
->set_last_viewed_by_me_date(options
.last_viewed_by_me_date
);
601 request
->set_mime_type(kFolderMimeType
);
602 request
->set_modified_date(options
.modified_date
);
603 request
->add_parent(parent_resource_id
);
604 request
->set_title(directory_title
);
605 request
->set_fields(kFileResourceFields
);
606 return sender_
->StartRequestWithRetry(request
);
609 CancelCallback
DriveAPIService::CopyResource(
610 const std::string
& resource_id
,
611 const std::string
& parent_resource_id
,
612 const std::string
& new_title
,
613 const base::Time
& last_modified
,
614 const GetResourceEntryCallback
& callback
) {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
616 DCHECK(!callback
.is_null());
618 FilesCopyRequest
* request
= new FilesCopyRequest(
619 sender_
.get(), url_generator_
,
620 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
621 request
->set_file_id(resource_id
);
622 request
->add_parent(parent_resource_id
);
623 request
->set_title(new_title
);
624 request
->set_modified_date(last_modified
);
625 request
->set_fields(kFileResourceFields
);
626 return sender_
->StartRequestWithRetry(request
);
629 CancelCallback
DriveAPIService::UpdateResource(
630 const std::string
& resource_id
,
631 const std::string
& parent_resource_id
,
632 const std::string
& new_title
,
633 const base::Time
& last_modified
,
634 const base::Time
& last_viewed_by_me
,
635 const GetResourceEntryCallback
& callback
) {
636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
637 DCHECK(!callback
.is_null());
639 FilesPatchRequest
* request
= new FilesPatchRequest(
640 sender_
.get(), url_generator_
,
641 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
642 request
->set_file_id(resource_id
);
643 request
->set_title(new_title
);
644 if (!parent_resource_id
.empty())
645 request
->add_parent(parent_resource_id
);
646 if (!last_modified
.is_null()) {
647 // Need to set setModifiedDate to true to overwrite modifiedDate.
648 request
->set_set_modified_date(true);
649 request
->set_modified_date(last_modified
);
651 if (!last_viewed_by_me
.is_null()) {
652 // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
653 // will be set to the request time (not the specified time via request).
654 request
->set_update_viewed_date(false);
655 request
->set_last_viewed_by_me_date(last_viewed_by_me
);
657 request
->set_fields(kFileResourceFields
);
658 return sender_
->StartRequestWithRetry(request
);
661 CancelCallback
DriveAPIService::RenameResource(
662 const std::string
& resource_id
,
663 const std::string
& new_title
,
664 const EntryActionCallback
& callback
) {
665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
666 DCHECK(!callback
.is_null());
668 FilesPatchRequest
* request
= new FilesPatchRequest(
669 sender_
.get(), url_generator_
,
670 base::Bind(&EntryActionCallbackAdapter
, callback
));
671 request
->set_file_id(resource_id
);
672 request
->set_title(new_title
);
673 request
->set_fields(kFileResourceFields
);
674 return sender_
->StartRequestWithRetry(request
);
677 CancelCallback
DriveAPIService::AddResourceToDirectory(
678 const std::string
& parent_resource_id
,
679 const std::string
& resource_id
,
680 const EntryActionCallback
& callback
) {
681 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
682 DCHECK(!callback
.is_null());
684 ChildrenInsertRequest
* request
=
685 new ChildrenInsertRequest(sender_
.get(), url_generator_
, callback
);
686 request
->set_folder_id(parent_resource_id
);
687 request
->set_id(resource_id
);
688 return sender_
->StartRequestWithRetry(request
);
691 CancelCallback
DriveAPIService::RemoveResourceFromDirectory(
692 const std::string
& parent_resource_id
,
693 const std::string
& resource_id
,
694 const EntryActionCallback
& callback
) {
695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
696 DCHECK(!callback
.is_null());
698 ChildrenDeleteRequest
* request
=
699 new ChildrenDeleteRequest(sender_
.get(), url_generator_
, callback
);
700 request
->set_child_id(resource_id
);
701 request
->set_folder_id(parent_resource_id
);
702 return sender_
->StartRequestWithRetry(request
);
705 CancelCallback
DriveAPIService::InitiateUploadNewFile(
706 const std::string
& content_type
,
707 int64 content_length
,
708 const std::string
& parent_resource_id
,
709 const std::string
& title
,
710 const InitiateUploadNewFileOptions
& options
,
711 const InitiateUploadCallback
& callback
) {
712 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
713 DCHECK(!callback
.is_null());
715 InitiateUploadNewFileRequest
* request
=
716 new InitiateUploadNewFileRequest(sender_
.get(),
723 request
->set_modified_date(options
.modified_date
);
724 request
->set_last_viewed_by_me_date(options
.last_viewed_by_me_date
);
725 return sender_
->StartRequestWithRetry(request
);
728 CancelCallback
DriveAPIService::InitiateUploadExistingFile(
729 const std::string
& content_type
,
730 int64 content_length
,
731 const std::string
& resource_id
,
732 const InitiateUploadExistingFileOptions
& options
,
733 const InitiateUploadCallback
& callback
) {
734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
735 DCHECK(!callback
.is_null());
737 InitiateUploadExistingFileRequest
* request
=
738 new InitiateUploadExistingFileRequest(sender_
.get(),
745 request
->set_parent_resource_id(options
.parent_resource_id
);
746 request
->set_title(options
.title
);
747 request
->set_modified_date(options
.modified_date
);
748 request
->set_last_viewed_by_me_date(options
.last_viewed_by_me_date
);
749 return sender_
->StartRequestWithRetry(request
);
752 CancelCallback
DriveAPIService::ResumeUpload(
753 const GURL
& upload_url
,
754 int64 start_position
,
756 int64 content_length
,
757 const std::string
& content_type
,
758 const base::FilePath
& local_file_path
,
759 const UploadRangeCallback
& callback
,
760 const ProgressCallback
& progress_callback
) {
761 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
762 DCHECK(!callback
.is_null());
764 return sender_
->StartRequestWithRetry(
765 new ResumeUploadRequest(
773 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun
,
778 CancelCallback
DriveAPIService::GetUploadStatus(
779 const GURL
& upload_url
,
780 int64 content_length
,
781 const UploadRangeCallback
& callback
) {
782 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
783 DCHECK(!callback
.is_null());
785 return sender_
->StartRequestWithRetry(new GetUploadStatusRequest(
789 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun
,
793 CancelCallback
DriveAPIService::AuthorizeApp(
794 const std::string
& resource_id
,
795 const std::string
& app_id
,
796 const AuthorizeAppCallback
& callback
) {
797 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
798 DCHECK(!callback
.is_null());
800 // Files.Authorize is only available for whitelisted clients like official
801 // Google Chrome. In other cases, we fall back to Files.Get that returns the
802 // same value as Files.Authorize without doing authorization. In that case,
803 // the app can open if it was authorized by other means (from whitelisted
804 // clients or drive.google.com web UI.)
805 if (google_apis::IsGoogleChromeAPIKeyUsed()) {
806 google_apis::drive::FilesAuthorizeRequest
* request
=
807 new google_apis::drive::FilesAuthorizeRequest(
808 sender_
.get(), url_generator_
,
809 base::Bind(&ExtractOpenUrlAndRun
, app_id
, callback
));
810 request
->set_app_id(app_id
);
811 request
->set_file_id(resource_id
);
812 request
->set_fields(kFileResourceOpenWithLinksFields
);
813 return sender_
->StartRequestWithRetry(request
);
815 FilesGetRequest
* request
= new FilesGetRequest(
816 sender_
.get(), url_generator_
,
817 base::Bind(&ExtractOpenUrlAndRun
, app_id
, callback
));
818 request
->set_file_id(resource_id
);
819 request
->set_fields(kFileResourceOpenWithLinksFields
);
820 return sender_
->StartRequestWithRetry(request
);
824 CancelCallback
DriveAPIService::UninstallApp(
825 const std::string
& app_id
,
826 const google_apis::EntryActionCallback
& callback
) {
827 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
828 DCHECK(!callback
.is_null());
830 google_apis::drive::AppsDeleteRequest
* request
=
831 new google_apis::drive::AppsDeleteRequest(sender_
.get(), url_generator_
,
833 request
->set_app_id(app_id
);
834 return sender_
->StartRequestWithRetry(request
);
837 CancelCallback
DriveAPIService::GetResourceListInDirectoryByWapi(
838 const std::string
& directory_resource_id
,
839 const google_apis::GetResourceListCallback
& callback
) {
840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
841 DCHECK(!directory_resource_id
.empty());
842 DCHECK(!callback
.is_null());
844 return sender_
->StartRequestWithRetry(
845 new GetResourceListRequest(sender_
.get(),
847 GURL(), // No override url
848 0, // start changestamp
849 std::string(), // empty search query
850 directory_resource_id
,
854 CancelCallback
DriveAPIService::GetRemainingResourceList(
855 const GURL
& next_link
,
856 const google_apis::GetResourceListCallback
& callback
) {
857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
858 DCHECK(!next_link
.is_empty());
859 DCHECK(!callback
.is_null());
861 return sender_
->StartRequestWithRetry(
862 new GetResourceListRequest(sender_
.get(),
865 0, // start changestamp
866 std::string(), // empty search query
867 std::string(), // no directory resource id
871 bool DriveAPIService::HasAccessToken() const {
872 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
873 return sender_
->auth_service()->HasAccessToken();
876 void DriveAPIService::RequestAccessToken(const AuthStatusCallback
& callback
) {
877 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
878 DCHECK(!callback
.is_null());
880 const std::string access_token
= sender_
->auth_service()->access_token();
881 if (!access_token
.empty()) {
882 callback
.Run(google_apis::HTTP_NOT_MODIFIED
, access_token
);
886 // Retrieve the new auth token.
887 sender_
->auth_service()->StartAuthentication(callback
);
890 bool DriveAPIService::HasRefreshToken() const {
891 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
892 return sender_
->auth_service()->HasRefreshToken();
895 void DriveAPIService::ClearAccessToken() {
896 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
897 sender_
->auth_service()->ClearAccessToken();
900 void DriveAPIService::ClearRefreshToken() {
901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
902 sender_
->auth_service()->ClearRefreshToken();
905 void DriveAPIService::OnOAuth2RefreshTokenChanged() {
906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
907 if (CanSendRequest()) {
909 DriveServiceObserver
, observers_
, OnReadyToSendRequests());
910 } else if (!HasRefreshToken()) {
912 DriveServiceObserver
, observers_
, OnRefreshTokenInvalid());