NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / drive / drive_api_service.cc
blobfc68e13e42305f1d75fe19d947e3bbd0960f5df7
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_,
537 google_apis::IsGoogleChromeAPIKeyUsed(),
538 callback));
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(),
553 url_generator_,
554 resource_id,
555 local_cache_path,
556 download_action_callback,
557 get_content_callback,
558 progress_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(),
717 url_generator_,
718 content_type,
719 content_length,
720 parent_resource_id,
721 title,
722 callback);
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(),
739 url_generator_,
740 content_type,
741 content_length,
742 resource_id,
743 options.etag,
744 callback);
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,
755 int64 end_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(
766 sender_.get(),
767 upload_url,
768 start_position,
769 end_position,
770 content_length,
771 content_type,
772 local_file_path,
773 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun,
774 callback),
775 progress_callback));
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(
786 sender_.get(),
787 upload_url,
788 content_length,
789 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun,
790 callback)));
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);
814 } else {
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_,
832 callback);
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(),
846 wapi_url_generator_,
847 GURL(), // No override url
848 0, // start changestamp
849 std::string(), // empty search query
850 directory_resource_id,
851 callback));
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(),
863 wapi_url_generator_,
864 next_link,
865 0, // start changestamp
866 std::string(), // empty search query
867 std::string(), // no directory resource id
868 callback));
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);
883 return;
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()) {
908 FOR_EACH_OBSERVER(
909 DriveServiceObserver, observers_, OnReadyToSendRequests());
910 } else if (!HasRefreshToken()) {
911 FOR_EACH_OBSERVER(
912 DriveServiceObserver, observers_, OnRefreshTokenInvalid());
916 } // namespace drive