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_
, callback
));
539 CancelCallback
DriveAPIService::DownloadFile(
540 const base::FilePath
& local_cache_path
,
541 const std::string
& resource_id
,
542 const DownloadActionCallback
& download_action_callback
,
543 const GetContentCallback
& get_content_callback
,
544 const ProgressCallback
& progress_callback
) {
545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
546 DCHECK(!download_action_callback
.is_null());
547 // get_content_callback may be null.
549 return sender_
->StartRequestWithRetry(
550 new DownloadFileRequest(sender_
.get(),
554 download_action_callback
,
555 get_content_callback
,
559 CancelCallback
DriveAPIService::DeleteResource(
560 const std::string
& resource_id
,
561 const std::string
& etag
,
562 const EntryActionCallback
& callback
) {
563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
564 DCHECK(!callback
.is_null());
566 FilesDeleteRequest
* request
= new FilesDeleteRequest(
567 sender_
.get(), url_generator_
, callback
);
568 request
->set_file_id(resource_id
);
569 request
->set_etag(etag
);
570 return sender_
->StartRequestWithRetry(request
);
573 CancelCallback
DriveAPIService::TrashResource(
574 const std::string
& resource_id
,
575 const EntryActionCallback
& callback
) {
576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
577 DCHECK(!callback
.is_null());
579 FilesTrashRequest
* request
= new FilesTrashRequest(
580 sender_
.get(), url_generator_
,
581 base::Bind(&EntryActionCallbackAdapter
, callback
));
582 request
->set_file_id(resource_id
);
583 request
->set_fields(kFileResourceFields
);
584 return sender_
->StartRequestWithRetry(request
);
587 CancelCallback
DriveAPIService::AddNewDirectory(
588 const std::string
& parent_resource_id
,
589 const std::string
& directory_title
,
590 const GetResourceEntryCallback
& callback
) {
591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
592 DCHECK(!callback
.is_null());
594 FilesInsertRequest
* request
= new FilesInsertRequest(
595 sender_
.get(), url_generator_
,
596 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
597 request
->set_mime_type(kFolderMimeType
);
598 request
->add_parent(parent_resource_id
);
599 request
->set_title(directory_title
);
600 request
->set_fields(kFileResourceFields
);
601 return sender_
->StartRequestWithRetry(request
);
604 CancelCallback
DriveAPIService::CopyResource(
605 const std::string
& resource_id
,
606 const std::string
& parent_resource_id
,
607 const std::string
& new_title
,
608 const base::Time
& last_modified
,
609 const GetResourceEntryCallback
& callback
) {
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
611 DCHECK(!callback
.is_null());
613 FilesCopyRequest
* request
= new FilesCopyRequest(
614 sender_
.get(), url_generator_
,
615 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
616 request
->set_file_id(resource_id
);
617 request
->add_parent(parent_resource_id
);
618 request
->set_title(new_title
);
619 request
->set_modified_date(last_modified
);
620 request
->set_fields(kFileResourceFields
);
621 return sender_
->StartRequestWithRetry(request
);
624 CancelCallback
DriveAPIService::UpdateResource(
625 const std::string
& resource_id
,
626 const std::string
& parent_resource_id
,
627 const std::string
& new_title
,
628 const base::Time
& last_modified
,
629 const base::Time
& last_viewed_by_me
,
630 const GetResourceEntryCallback
& callback
) {
631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
632 DCHECK(!callback
.is_null());
634 FilesPatchRequest
* request
= new FilesPatchRequest(
635 sender_
.get(), url_generator_
,
636 base::Bind(&ConvertFileEntryToResourceEntryAndRun
, callback
));
637 request
->set_file_id(resource_id
);
638 request
->set_title(new_title
);
639 if (!parent_resource_id
.empty())
640 request
->add_parent(parent_resource_id
);
641 if (!last_modified
.is_null()) {
642 // Need to set setModifiedDate to true to overwrite modifiedDate.
643 request
->set_set_modified_date(true);
644 request
->set_modified_date(last_modified
);
646 if (!last_viewed_by_me
.is_null()) {
647 // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
648 // will be set to the request time (not the specified time via request).
649 request
->set_update_viewed_date(false);
650 request
->set_last_viewed_by_me_date(last_viewed_by_me
);
652 request
->set_fields(kFileResourceFields
);
653 return sender_
->StartRequestWithRetry(request
);
656 CancelCallback
DriveAPIService::RenameResource(
657 const std::string
& resource_id
,
658 const std::string
& new_title
,
659 const EntryActionCallback
& callback
) {
660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
661 DCHECK(!callback
.is_null());
663 FilesPatchRequest
* request
= new FilesPatchRequest(
664 sender_
.get(), url_generator_
,
665 base::Bind(&EntryActionCallbackAdapter
, callback
));
666 request
->set_file_id(resource_id
);
667 request
->set_title(new_title
);
668 request
->set_fields(kFileResourceFields
);
669 return sender_
->StartRequestWithRetry(request
);
672 CancelCallback
DriveAPIService::AddResourceToDirectory(
673 const std::string
& parent_resource_id
,
674 const std::string
& resource_id
,
675 const EntryActionCallback
& callback
) {
676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
677 DCHECK(!callback
.is_null());
679 ChildrenInsertRequest
* request
=
680 new ChildrenInsertRequest(sender_
.get(), url_generator_
, callback
);
681 request
->set_folder_id(parent_resource_id
);
682 request
->set_id(resource_id
);
683 return sender_
->StartRequestWithRetry(request
);
686 CancelCallback
DriveAPIService::RemoveResourceFromDirectory(
687 const std::string
& parent_resource_id
,
688 const std::string
& resource_id
,
689 const EntryActionCallback
& callback
) {
690 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
691 DCHECK(!callback
.is_null());
693 ChildrenDeleteRequest
* request
=
694 new ChildrenDeleteRequest(sender_
.get(), url_generator_
, callback
);
695 request
->set_child_id(resource_id
);
696 request
->set_folder_id(parent_resource_id
);
697 return sender_
->StartRequestWithRetry(request
);
700 CancelCallback
DriveAPIService::InitiateUploadNewFile(
701 const std::string
& content_type
,
702 int64 content_length
,
703 const std::string
& parent_resource_id
,
704 const std::string
& title
,
705 const InitiateUploadCallback
& callback
) {
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
707 DCHECK(!callback
.is_null());
709 return sender_
->StartRequestWithRetry(
710 new InitiateUploadNewFileRequest(
720 CancelCallback
DriveAPIService::InitiateUploadExistingFile(
721 const std::string
& content_type
,
722 int64 content_length
,
723 const std::string
& resource_id
,
724 const std::string
& etag
,
725 const InitiateUploadCallback
& callback
) {
726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
727 DCHECK(!callback
.is_null());
729 return sender_
->StartRequestWithRetry(
730 new InitiateUploadExistingFileRequest(
740 CancelCallback
DriveAPIService::ResumeUpload(
741 const GURL
& upload_url
,
742 int64 start_position
,
744 int64 content_length
,
745 const std::string
& content_type
,
746 const base::FilePath
& local_file_path
,
747 const UploadRangeCallback
& callback
,
748 const ProgressCallback
& progress_callback
) {
749 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
750 DCHECK(!callback
.is_null());
752 return sender_
->StartRequestWithRetry(
753 new ResumeUploadRequest(
761 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun
,
766 CancelCallback
DriveAPIService::GetUploadStatus(
767 const GURL
& upload_url
,
768 int64 content_length
,
769 const UploadRangeCallback
& callback
) {
770 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
771 DCHECK(!callback
.is_null());
773 return sender_
->StartRequestWithRetry(new GetUploadStatusRequest(
777 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun
,
781 CancelCallback
DriveAPIService::AuthorizeApp(
782 const std::string
& resource_id
,
783 const std::string
& app_id
,
784 const AuthorizeAppCallback
& callback
) {
785 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
786 DCHECK(!callback
.is_null());
788 // Files.Authorize is only available for whitelisted clients like official
789 // Google Chrome. In other cases, we fall back to Files.Get that returns the
790 // same value as Files.Authorize without doing authorization. In that case,
791 // the app can open if it was authorized by other means (from whitelisted
792 // clients or drive.google.com web UI.)
793 if (google_apis::IsGoogleChromeAPIKeyUsed()) {
794 google_apis::drive::FilesAuthorizeRequest
* request
=
795 new google_apis::drive::FilesAuthorizeRequest(
796 sender_
.get(), url_generator_
,
797 base::Bind(&ExtractOpenUrlAndRun
, app_id
, callback
));
798 request
->set_app_id(app_id
);
799 request
->set_file_id(resource_id
);
800 request
->set_fields(kFileResourceOpenWithLinksFields
);
801 return sender_
->StartRequestWithRetry(request
);
803 FilesGetRequest
* request
= new FilesGetRequest(
804 sender_
.get(), url_generator_
,
805 base::Bind(&ExtractOpenUrlAndRun
, app_id
, callback
));
806 request
->set_file_id(resource_id
);
807 request
->set_fields(kFileResourceOpenWithLinksFields
);
808 return sender_
->StartRequestWithRetry(request
);
812 CancelCallback
DriveAPIService::UninstallApp(
813 const std::string
& app_id
,
814 const google_apis::EntryActionCallback
& callback
) {
815 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
816 DCHECK(!callback
.is_null());
818 google_apis::drive::AppsDeleteRequest
* request
=
819 new google_apis::drive::AppsDeleteRequest(sender_
.get(), url_generator_
,
821 request
->set_app_id(app_id
);
822 return sender_
->StartRequestWithRetry(request
);
825 CancelCallback
DriveAPIService::GetResourceListInDirectoryByWapi(
826 const std::string
& directory_resource_id
,
827 const google_apis::GetResourceListCallback
& callback
) {
828 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
829 DCHECK(!directory_resource_id
.empty());
830 DCHECK(!callback
.is_null());
832 return sender_
->StartRequestWithRetry(
833 new GetResourceListRequest(sender_
.get(),
835 GURL(), // No override url
836 0, // start changestamp
837 std::string(), // empty search query
838 directory_resource_id
,
842 CancelCallback
DriveAPIService::GetRemainingResourceList(
843 const GURL
& next_link
,
844 const google_apis::GetResourceListCallback
& callback
) {
845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
846 DCHECK(!next_link
.is_empty());
847 DCHECK(!callback
.is_null());
849 return sender_
->StartRequestWithRetry(
850 new GetResourceListRequest(sender_
.get(),
853 0, // start changestamp
854 std::string(), // empty search query
855 std::string(), // no directory resource id
859 bool DriveAPIService::HasAccessToken() const {
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
861 return sender_
->auth_service()->HasAccessToken();
864 void DriveAPIService::RequestAccessToken(const AuthStatusCallback
& callback
) {
865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
866 DCHECK(!callback
.is_null());
868 const std::string access_token
= sender_
->auth_service()->access_token();
869 if (!access_token
.empty()) {
870 callback
.Run(google_apis::HTTP_NOT_MODIFIED
, access_token
);
874 // Retrieve the new auth token.
875 sender_
->auth_service()->StartAuthentication(callback
);
878 bool DriveAPIService::HasRefreshToken() const {
879 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
880 return sender_
->auth_service()->HasRefreshToken();
883 void DriveAPIService::ClearAccessToken() {
884 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
885 sender_
->auth_service()->ClearAccessToken();
888 void DriveAPIService::ClearRefreshToken() {
889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
890 sender_
->auth_service()->ClearRefreshToken();
893 void DriveAPIService::OnOAuth2RefreshTokenChanged() {
894 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
895 if (CanSendRequest()) {
897 DriveServiceObserver
, observers_
, OnReadyToSendRequests());
898 } else if (!HasRefreshToken()) {
900 DriveServiceObserver
, observers_
, OnRefreshTokenInvalid());