Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / drive / drive_api_service.cc
blob05081706cb228ebafb6b9900cede5496ab890bae
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"
7 #include <string>
8 #include <vector>
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;
78 namespace drive {
80 namespace {
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,"
125 "largestChangeId";
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
137 // UI thread.
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());
145 if (!value) {
146 callback.Run(error, scoped_ptr<ResourceEntry>());
147 return;
150 // Converting to ResourceEntry is cheap enough to do on UI thread.
151 scoped_ptr<ResourceEntry> entry =
152 util::ConvertFileResourceToResourceEntry(*value);
153 if (!entry) {
154 callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>());
155 return;
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());
177 if (!value) {
178 callback.Run(error, scoped_ptr<ResourceList>());
179 return;
182 // Convert the value on blocking pool.
183 base::PostTaskAndReplyWithResult(
184 blocking_task_runner.get(),
185 FROM_HERE,
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());
206 if (!value) {
207 callback.Run(error, scoped_ptr<ResourceList>());
208 return;
211 // Convert the value on blocking pool.
212 base::PostTaskAndReplyWithResult(
213 blocking_task_runner.get(),
214 FROM_HERE,
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());
228 if (!value) {
229 callback.Run(response, scoped_ptr<ResourceEntry>());
230 return;
233 // Converting to ResourceEntry is cheap enough to do on UI thread.
234 scoped_ptr<ResourceEntry> entry =
235 util::ConvertFileResourceToResourceEntry(*value);
236 if (!entry) {
237 callback.Run(UploadRangeResponse(GDATA_PARSE_ERROR,
238 response.start_position_received,
239 response.end_position_received),
240 scoped_ptr<ResourceEntry>());
241 return;
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());
254 if (!value) {
255 callback.Run(error, GURL());
256 return;
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);
264 return;
268 // Not found.
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) {
276 callback.Run(error);
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";
283 } // namespace
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));
304 if (sender_.get())
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_,
321 account_id,
322 url_request_context_getter_.get(),
323 scopes),
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
379 // to client side.
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());
418 std::string query;
419 base::StringAppendF(&query, "title = '%s'",
420 drive::util::EscapeQueryStringValue(title).c_str());
421 if (!directory_resource_id.empty()) {
422 base::StringAppendF(
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(
462 sender_.get(),
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(
478 sender_.get(),
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(),
513 wapi_url_generator_,
514 resource_id,
515 embed_origin,
516 base::Bind(&util::ParseShareUrlAndRun,
517 callback)));
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(),
551 url_generator_,
552 resource_id,
553 local_cache_path,
554 download_action_callback,
555 get_content_callback,
556 progress_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(
711 sender_.get(),
712 url_generator_,
713 content_type,
714 content_length,
715 parent_resource_id,
716 title,
717 callback));
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(
731 sender_.get(),
732 url_generator_,
733 content_type,
734 content_length,
735 resource_id,
736 etag,
737 callback));
740 CancelCallback DriveAPIService::ResumeUpload(
741 const GURL& upload_url,
742 int64 start_position,
743 int64 end_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(
754 sender_.get(),
755 upload_url,
756 start_position,
757 end_position,
758 content_length,
759 content_type,
760 local_file_path,
761 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun,
762 callback),
763 progress_callback));
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(
774 sender_.get(),
775 upload_url,
776 content_length,
777 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun,
778 callback)));
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);
802 } else {
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_,
820 callback);
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(),
834 wapi_url_generator_,
835 GURL(), // No override url
836 0, // start changestamp
837 std::string(), // empty search query
838 directory_resource_id,
839 callback));
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(),
851 wapi_url_generator_,
852 next_link,
853 0, // start changestamp
854 std::string(), // empty search query
855 std::string(), // no directory resource id
856 callback));
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);
871 return;
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()) {
896 FOR_EACH_OBSERVER(
897 DriveServiceObserver, observers_, OnReadyToSendRequests());
898 } else if (!HasRefreshToken()) {
899 FOR_EACH_OBSERVER(
900 DriveServiceObserver, observers_, OnRefreshTokenInvalid());
904 } // namespace drive