• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/drive/drive_api_service.h"
6 
7 #include <string>
8 #include <vector>
9 
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"
26 
27 using content::BrowserThread;
28 using google_apis::AboutResourceCallback;
29 using google_apis::AppList;
30 using google_apis::AppListCallback;
31 using google_apis::AuthStatusCallback;
32 using google_apis::AuthorizeAppCallback;
33 using google_apis::CancelCallback;
34 using google_apis::ChangeList;
35 using google_apis::ChangeListCallback;
36 using google_apis::DownloadActionCallback;
37 using google_apis::EntryActionCallback;
38 using google_apis::FileList;
39 using google_apis::FileListCallback;
40 using google_apis::FileResource;
41 using google_apis::FileResourceCallback;
42 using google_apis::GDATA_OTHER_ERROR;
43 using google_apis::GDATA_PARSE_ERROR;
44 using google_apis::GDataErrorCode;
45 using google_apis::GetContentCallback;
46 using google_apis::GetResourceEntryRequest;
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::UploadRangeResponse;
55 using google_apis::drive::AboutGetRequest;
56 using google_apis::drive::AppsListRequest;
57 using google_apis::drive::ChangesListRequest;
58 using google_apis::drive::ChangesListNextPageRequest;
59 using google_apis::drive::ChildrenDeleteRequest;
60 using google_apis::drive::ChildrenInsertRequest;
61 using google_apis::drive::DownloadFileRequest;
62 using google_apis::drive::FilesCopyRequest;
63 using google_apis::drive::FilesGetRequest;
64 using google_apis::drive::FilesInsertRequest;
65 using google_apis::drive::FilesPatchRequest;
66 using google_apis::drive::FilesListRequest;
67 using google_apis::drive::FilesListNextPageRequest;
68 using google_apis::drive::FilesDeleteRequest;
69 using google_apis::drive::FilesTrashRequest;
70 using google_apis::drive::GetUploadStatusRequest;
71 using google_apis::drive::InitiateUploadExistingFileRequest;
72 using google_apis::drive::InitiateUploadNewFileRequest;
73 using google_apis::drive::ResumeUploadRequest;
74 using google_apis::drive::UploadRangeCallback;
75 
76 namespace drive {
77 
78 namespace {
79 
80 // OAuth2 scopes for Drive API.
81 const char kDriveScope[] = "https://www.googleapis.com/auth/drive";
82 const char kDriveAppsReadonlyScope[] =
83     "https://www.googleapis.com/auth/drive.apps.readonly";
84 
85 // Mime type to create a directory.
86 const char kFolderMimeType[] = "application/vnd.google-apps.folder";
87 
88 // Max number of file entries to be fetched in a single http request.
89 //
90 // The larger the number is,
91 // - The total running time to fetch the whole file list will become shorter.
92 // - The running time for a single request tends to become longer.
93 // Since the file list fetching is a completely background task, for our side,
94 // only the total time matters. However, the server seems to have a time limit
95 // per single request, which disables us to set the largest value (1000).
96 // TODO(kinaba): make it larger when the server gets faster.
97 const int kMaxNumFilesResourcePerRequest = 300;
98 const int kMaxNumFilesResourcePerRequestForSearch = 100;
99 
100 // For performance, we declare all fields we use.
101 const char kAboutResourceFields[] =
102     "kind,quotaBytesTotal,quotaBytesUsed,largestChangeId,rootFolderId";
103 const char kFileResourceFields[] =
104     "kind,id,title,createdDate,sharedWithMeDate,mimeType,"
105     "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
106     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
107     "parents(id,parentLink),alternateLink,"
108     "modifiedDate,lastViewedByMeDate,shared";
109 const char kFileResourceOpenWithLinksFields[] =
110     "kind,id,openWithLinks/*";
111 const char kFileListFields[] =
112     "kind,items(kind,id,title,createdDate,sharedWithMeDate,"
113     "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
114     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
115     "parents(id,parentLink),alternateLink,"
116     "modifiedDate,lastViewedByMeDate,shared),nextLink";
117 const char kChangeListFields[] =
118     "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,"
119     "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
120     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
121     "parents(id,parentLink),alternateLink,modifiedDate,"
122     "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink,"
123     "largestChangeId";
124 
ExtractOpenUrlAndRun(const std::string & app_id,const AuthorizeAppCallback & callback,GDataErrorCode error,scoped_ptr<FileResource> value)125 void ExtractOpenUrlAndRun(const std::string& app_id,
126                           const AuthorizeAppCallback& callback,
127                           GDataErrorCode error,
128                           scoped_ptr<FileResource> value) {
129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
130   DCHECK(!callback.is_null());
131 
132   if (!value) {
133     callback.Run(error, GURL());
134     return;
135   }
136 
137   const std::vector<FileResource::OpenWithLink>& open_with_links =
138       value->open_with_links();
139   for (size_t i = 0; i < open_with_links.size(); ++i) {
140     if (open_with_links[i].app_id == app_id) {
141       callback.Run(HTTP_SUCCESS, open_with_links[i].open_url);
142       return;
143     }
144   }
145 
146   // Not found.
147   callback.Run(GDATA_OTHER_ERROR, GURL());
148 }
149 
150 // Ignores the |entry|, and runs the |callback|.
EntryActionCallbackAdapter(const EntryActionCallback & callback,GDataErrorCode error,scoped_ptr<FileResource> entry)151 void EntryActionCallbackAdapter(
152     const EntryActionCallback& callback,
153     GDataErrorCode error, scoped_ptr<FileResource> entry) {
154   callback.Run(error);
155 }
156 
157 // The resource ID for the root directory for Drive API is defined in the spec:
158 // https://developers.google.com/drive/folder
159 const char kDriveApiRootDirectoryResourceId[] = "root";
160 
161 }  // namespace
162 
DriveAPIService(OAuth2TokenService * oauth2_token_service,net::URLRequestContextGetter * url_request_context_getter,base::SequencedTaskRunner * blocking_task_runner,const GURL & base_url,const GURL & base_download_url,const GURL & wapi_base_url,const std::string & custom_user_agent)163 DriveAPIService::DriveAPIService(
164     OAuth2TokenService* oauth2_token_service,
165     net::URLRequestContextGetter* url_request_context_getter,
166     base::SequencedTaskRunner* blocking_task_runner,
167     const GURL& base_url,
168     const GURL& base_download_url,
169     const GURL& wapi_base_url,
170     const std::string& custom_user_agent)
171     : oauth2_token_service_(oauth2_token_service),
172       url_request_context_getter_(url_request_context_getter),
173       blocking_task_runner_(blocking_task_runner),
174       url_generator_(base_url, base_download_url),
175       wapi_url_generator_(wapi_base_url),
176       custom_user_agent_(custom_user_agent) {
177   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178 }
179 
~DriveAPIService()180 DriveAPIService::~DriveAPIService() {
181   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182   if (sender_.get())
183     sender_->auth_service()->RemoveObserver(this);
184 }
185 
Initialize(const std::string & account_id)186 void DriveAPIService::Initialize(const std::string& account_id) {
187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
188 
189   std::vector<std::string> scopes;
190   scopes.push_back(kDriveScope);
191   scopes.push_back(kDriveAppsReadonlyScope);
192   scopes.push_back(util::kDriveAppsScope);
193 
194   // GData WAPI token for GetShareUrl().
195   scopes.push_back(util::kDocsListScope);
196 
197   sender_.reset(new RequestSender(
198       new google_apis::AuthService(oauth2_token_service_,
199                                    account_id,
200                                    url_request_context_getter_.get(),
201                                    scopes),
202       url_request_context_getter_.get(),
203       blocking_task_runner_.get(),
204       custom_user_agent_));
205   sender_->auth_service()->AddObserver(this);
206 }
207 
AddObserver(DriveServiceObserver * observer)208 void DriveAPIService::AddObserver(DriveServiceObserver* observer) {
209   observers_.AddObserver(observer);
210 }
211 
RemoveObserver(DriveServiceObserver * observer)212 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) {
213   observers_.RemoveObserver(observer);
214 }
215 
CanSendRequest() const216 bool DriveAPIService::CanSendRequest() const {
217   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218 
219   return HasRefreshToken();
220 }
221 
GetResourceIdCanonicalizer() const222 ResourceIdCanonicalizer DriveAPIService::GetResourceIdCanonicalizer() const {
223   return base::Bind(&drive::util::CanonicalizeResourceId);
224 }
225 
GetRootResourceId() const226 std::string DriveAPIService::GetRootResourceId() const {
227   return kDriveApiRootDirectoryResourceId;
228 }
229 
GetAllFileList(const FileListCallback & callback)230 CancelCallback DriveAPIService::GetAllFileList(
231     const FileListCallback& callback) {
232   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233   DCHECK(!callback.is_null());
234 
235   FilesListRequest* request = new FilesListRequest(
236       sender_.get(), url_generator_, callback);
237   request->set_max_results(kMaxNumFilesResourcePerRequest);
238   request->set_q("trashed = false");  // Exclude trashed files.
239   request->set_fields(kFileListFields);
240   return sender_->StartRequestWithRetry(request);
241 }
242 
GetFileListInDirectory(const std::string & directory_resource_id,const FileListCallback & callback)243 CancelCallback DriveAPIService::GetFileListInDirectory(
244     const std::string& directory_resource_id,
245     const FileListCallback& callback) {
246   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247   DCHECK(!directory_resource_id.empty());
248   DCHECK(!callback.is_null());
249 
250   // Because children.list method on Drive API v2 returns only the list of
251   // children's references, but we need all file resource list.
252   // So, here we use files.list method instead, with setting parents query.
253   // After the migration from GData WAPI to Drive API v2, we should clean the
254   // code up by moving the responsibility to include "parents" in the query
255   // to client side.
256   // We aren't interested in files in trash in this context, neither.
257   FilesListRequest* request = new FilesListRequest(
258       sender_.get(), url_generator_, callback);
259   request->set_max_results(kMaxNumFilesResourcePerRequest);
260   request->set_q(base::StringPrintf(
261       "'%s' in parents and trashed = false",
262       drive::util::EscapeQueryStringValue(directory_resource_id).c_str()));
263   request->set_fields(kFileListFields);
264   return sender_->StartRequestWithRetry(request);
265 }
266 
Search(const std::string & search_query,const FileListCallback & callback)267 CancelCallback DriveAPIService::Search(
268     const std::string& search_query,
269     const FileListCallback& callback) {
270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271   DCHECK(!search_query.empty());
272   DCHECK(!callback.is_null());
273 
274   FilesListRequest* request = new FilesListRequest(
275       sender_.get(), url_generator_, callback);
276   request->set_max_results(kMaxNumFilesResourcePerRequestForSearch);
277   request->set_q(drive::util::TranslateQuery(search_query));
278   request->set_fields(kFileListFields);
279   return sender_->StartRequestWithRetry(request);
280 }
281 
SearchByTitle(const std::string & title,const std::string & directory_resource_id,const FileListCallback & callback)282 CancelCallback DriveAPIService::SearchByTitle(
283     const std::string& title,
284     const std::string& directory_resource_id,
285     const FileListCallback& callback) {
286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287   DCHECK(!title.empty());
288   DCHECK(!callback.is_null());
289 
290   std::string query;
291   base::StringAppendF(&query, "title = '%s'",
292                       drive::util::EscapeQueryStringValue(title).c_str());
293   if (!directory_resource_id.empty()) {
294     base::StringAppendF(
295         &query, " and '%s' in parents",
296         drive::util::EscapeQueryStringValue(directory_resource_id).c_str());
297   }
298   query += " and trashed = false";
299 
300   FilesListRequest* request = new FilesListRequest(
301       sender_.get(), url_generator_, callback);
302   request->set_max_results(kMaxNumFilesResourcePerRequest);
303   request->set_q(query);
304   request->set_fields(kFileListFields);
305   return sender_->StartRequestWithRetry(request);
306 }
307 
GetChangeList(int64 start_changestamp,const ChangeListCallback & callback)308 CancelCallback DriveAPIService::GetChangeList(
309     int64 start_changestamp,
310     const ChangeListCallback& callback) {
311   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312   DCHECK(!callback.is_null());
313 
314   ChangesListRequest* request = new ChangesListRequest(
315       sender_.get(), url_generator_, callback);
316   request->set_max_results(kMaxNumFilesResourcePerRequest);
317   request->set_start_change_id(start_changestamp);
318   request->set_fields(kChangeListFields);
319   return sender_->StartRequestWithRetry(request);
320 }
321 
GetRemainingChangeList(const GURL & next_link,const ChangeListCallback & callback)322 CancelCallback DriveAPIService::GetRemainingChangeList(
323     const GURL& next_link,
324     const ChangeListCallback& callback) {
325   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326   DCHECK(!next_link.is_empty());
327   DCHECK(!callback.is_null());
328 
329   ChangesListNextPageRequest* request = new ChangesListNextPageRequest(
330       sender_.get(), callback);
331   request->set_next_link(next_link);
332   request->set_fields(kChangeListFields);
333   return sender_->StartRequestWithRetry(request);
334 }
335 
GetRemainingFileList(const GURL & next_link,const FileListCallback & callback)336 CancelCallback DriveAPIService::GetRemainingFileList(
337     const GURL& next_link,
338     const FileListCallback& callback) {
339   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340   DCHECK(!next_link.is_empty());
341   DCHECK(!callback.is_null());
342 
343   FilesListNextPageRequest* request = new FilesListNextPageRequest(
344       sender_.get(), callback);
345   request->set_next_link(next_link);
346   request->set_fields(kFileListFields);
347   return sender_->StartRequestWithRetry(request);
348 }
349 
GetFileResource(const std::string & resource_id,const FileResourceCallback & callback)350 CancelCallback DriveAPIService::GetFileResource(
351     const std::string& resource_id,
352     const FileResourceCallback& callback) {
353   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
354   DCHECK(!callback.is_null());
355 
356   FilesGetRequest* request = new FilesGetRequest(
357       sender_.get(), url_generator_, callback);
358   request->set_file_id(resource_id);
359   request->set_fields(kFileResourceFields);
360   return sender_->StartRequestWithRetry(request);
361 }
362 
GetShareUrl(const std::string & resource_id,const GURL & embed_origin,const GetShareUrlCallback & callback)363 CancelCallback DriveAPIService::GetShareUrl(
364     const std::string& resource_id,
365     const GURL& embed_origin,
366     const GetShareUrlCallback& callback) {
367   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
368   DCHECK(!callback.is_null());
369 
370   // Unfortunately "share url" is not yet supported on Drive API v2.
371   // So, as a fallback, we use GData WAPI protocol for this method.
372   // TODO(hidehiko): Get rid of this implementation when share url is
373   // supported on Drive API v2.
374   return sender_->StartRequestWithRetry(
375       new GetResourceEntryRequest(sender_.get(),
376                                   wapi_url_generator_,
377                                   resource_id,
378                                   embed_origin,
379                                   base::Bind(&util::ParseShareUrlAndRun,
380                                              callback)));
381 }
382 
GetAboutResource(const AboutResourceCallback & callback)383 CancelCallback DriveAPIService::GetAboutResource(
384     const AboutResourceCallback& callback) {
385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
386   DCHECK(!callback.is_null());
387 
388   AboutGetRequest* request =
389       new AboutGetRequest(sender_.get(), url_generator_, callback);
390   request->set_fields(kAboutResourceFields);
391   return sender_->StartRequestWithRetry(request);
392 }
393 
GetAppList(const AppListCallback & callback)394 CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) {
395   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396   DCHECK(!callback.is_null());
397 
398   return sender_->StartRequestWithRetry(
399       new AppsListRequest(sender_.get(), url_generator_,
400                           google_apis::IsGoogleChromeAPIKeyUsed(),
401                           callback));
402 }
403 
DownloadFile(const base::FilePath & local_cache_path,const std::string & resource_id,const DownloadActionCallback & download_action_callback,const GetContentCallback & get_content_callback,const ProgressCallback & progress_callback)404 CancelCallback DriveAPIService::DownloadFile(
405     const base::FilePath& local_cache_path,
406     const std::string& resource_id,
407     const DownloadActionCallback& download_action_callback,
408     const GetContentCallback& get_content_callback,
409     const ProgressCallback& progress_callback) {
410   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411   DCHECK(!download_action_callback.is_null());
412   // get_content_callback may be null.
413 
414   return sender_->StartRequestWithRetry(
415       new DownloadFileRequest(sender_.get(),
416                               url_generator_,
417                               resource_id,
418                               local_cache_path,
419                               download_action_callback,
420                               get_content_callback,
421                               progress_callback));
422 }
423 
DeleteResource(const std::string & resource_id,const std::string & etag,const EntryActionCallback & callback)424 CancelCallback DriveAPIService::DeleteResource(
425     const std::string& resource_id,
426     const std::string& etag,
427     const EntryActionCallback& callback) {
428   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429   DCHECK(!callback.is_null());
430 
431   FilesDeleteRequest* request = new FilesDeleteRequest(
432       sender_.get(), url_generator_, callback);
433   request->set_file_id(resource_id);
434   request->set_etag(etag);
435   return sender_->StartRequestWithRetry(request);
436 }
437 
TrashResource(const std::string & resource_id,const EntryActionCallback & callback)438 CancelCallback DriveAPIService::TrashResource(
439     const std::string& resource_id,
440     const EntryActionCallback& callback) {
441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
442   DCHECK(!callback.is_null());
443 
444   FilesTrashRequest* request = new FilesTrashRequest(
445       sender_.get(), url_generator_,
446       base::Bind(&EntryActionCallbackAdapter, callback));
447   request->set_file_id(resource_id);
448   request->set_fields(kFileResourceFields);
449   return sender_->StartRequestWithRetry(request);
450 }
451 
AddNewDirectory(const std::string & parent_resource_id,const std::string & directory_title,const AddNewDirectoryOptions & options,const FileResourceCallback & callback)452 CancelCallback DriveAPIService::AddNewDirectory(
453     const std::string& parent_resource_id,
454     const std::string& directory_title,
455     const AddNewDirectoryOptions& options,
456     const FileResourceCallback& callback) {
457   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
458   DCHECK(!callback.is_null());
459 
460   FilesInsertRequest* request = new FilesInsertRequest(
461       sender_.get(), url_generator_, callback);
462   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
463   request->set_mime_type(kFolderMimeType);
464   request->set_modified_date(options.modified_date);
465   request->add_parent(parent_resource_id);
466   request->set_title(directory_title);
467   request->set_fields(kFileResourceFields);
468   return sender_->StartRequestWithRetry(request);
469 }
470 
CopyResource(const std::string & resource_id,const std::string & parent_resource_id,const std::string & new_title,const base::Time & last_modified,const FileResourceCallback & callback)471 CancelCallback DriveAPIService::CopyResource(
472     const std::string& resource_id,
473     const std::string& parent_resource_id,
474     const std::string& new_title,
475     const base::Time& last_modified,
476     const FileResourceCallback& callback) {
477   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
478   DCHECK(!callback.is_null());
479 
480   FilesCopyRequest* request = new FilesCopyRequest(
481       sender_.get(), url_generator_, callback);
482   request->set_file_id(resource_id);
483   request->add_parent(parent_resource_id);
484   request->set_title(new_title);
485   request->set_modified_date(last_modified);
486   request->set_fields(kFileResourceFields);
487   return sender_->StartRequestWithRetry(request);
488 }
489 
UpdateResource(const std::string & resource_id,const std::string & parent_resource_id,const std::string & new_title,const base::Time & last_modified,const base::Time & last_viewed_by_me,const FileResourceCallback & callback)490 CancelCallback DriveAPIService::UpdateResource(
491     const std::string& resource_id,
492     const std::string& parent_resource_id,
493     const std::string& new_title,
494     const base::Time& last_modified,
495     const base::Time& last_viewed_by_me,
496     const FileResourceCallback& callback) {
497   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
498   DCHECK(!callback.is_null());
499 
500   FilesPatchRequest* request = new FilesPatchRequest(
501       sender_.get(), url_generator_, callback);
502   request->set_file_id(resource_id);
503   request->set_title(new_title);
504   if (!parent_resource_id.empty())
505     request->add_parent(parent_resource_id);
506   if (!last_modified.is_null()) {
507     // Need to set setModifiedDate to true to overwrite modifiedDate.
508     request->set_set_modified_date(true);
509     request->set_modified_date(last_modified);
510   }
511   if (!last_viewed_by_me.is_null()) {
512     // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
513     // will be set to the request time (not the specified time via request).
514     request->set_update_viewed_date(false);
515     request->set_last_viewed_by_me_date(last_viewed_by_me);
516   }
517   request->set_fields(kFileResourceFields);
518   return sender_->StartRequestWithRetry(request);
519 }
520 
RenameResource(const std::string & resource_id,const std::string & new_title,const EntryActionCallback & callback)521 CancelCallback DriveAPIService::RenameResource(
522     const std::string& resource_id,
523     const std::string& new_title,
524     const EntryActionCallback& callback) {
525   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
526   DCHECK(!callback.is_null());
527 
528   FilesPatchRequest* request = new FilesPatchRequest(
529       sender_.get(), url_generator_,
530       base::Bind(&EntryActionCallbackAdapter, callback));
531   request->set_file_id(resource_id);
532   request->set_title(new_title);
533   request->set_fields(kFileResourceFields);
534   return sender_->StartRequestWithRetry(request);
535 }
536 
AddResourceToDirectory(const std::string & parent_resource_id,const std::string & resource_id,const EntryActionCallback & callback)537 CancelCallback DriveAPIService::AddResourceToDirectory(
538     const std::string& parent_resource_id,
539     const std::string& resource_id,
540     const EntryActionCallback& callback) {
541   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
542   DCHECK(!callback.is_null());
543 
544   ChildrenInsertRequest* request =
545       new ChildrenInsertRequest(sender_.get(), url_generator_, callback);
546   request->set_folder_id(parent_resource_id);
547   request->set_id(resource_id);
548   return sender_->StartRequestWithRetry(request);
549 }
550 
RemoveResourceFromDirectory(const std::string & parent_resource_id,const std::string & resource_id,const EntryActionCallback & callback)551 CancelCallback DriveAPIService::RemoveResourceFromDirectory(
552     const std::string& parent_resource_id,
553     const std::string& resource_id,
554     const EntryActionCallback& callback) {
555   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
556   DCHECK(!callback.is_null());
557 
558   ChildrenDeleteRequest* request =
559       new ChildrenDeleteRequest(sender_.get(), url_generator_, callback);
560   request->set_child_id(resource_id);
561   request->set_folder_id(parent_resource_id);
562   return sender_->StartRequestWithRetry(request);
563 }
564 
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const InitiateUploadNewFileOptions & options,const InitiateUploadCallback & callback)565 CancelCallback DriveAPIService::InitiateUploadNewFile(
566     const std::string& content_type,
567     int64 content_length,
568     const std::string& parent_resource_id,
569     const std::string& title,
570     const InitiateUploadNewFileOptions& options,
571     const InitiateUploadCallback& callback) {
572   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
573   DCHECK(!callback.is_null());
574 
575   InitiateUploadNewFileRequest* request =
576       new InitiateUploadNewFileRequest(sender_.get(),
577                                        url_generator_,
578                                        content_type,
579                                        content_length,
580                                        parent_resource_id,
581                                        title,
582                                        callback);
583   request->set_modified_date(options.modified_date);
584   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
585   return sender_->StartRequestWithRetry(request);
586 }
587 
InitiateUploadExistingFile(const std::string & content_type,int64 content_length,const std::string & resource_id,const InitiateUploadExistingFileOptions & options,const InitiateUploadCallback & callback)588 CancelCallback DriveAPIService::InitiateUploadExistingFile(
589     const std::string& content_type,
590     int64 content_length,
591     const std::string& resource_id,
592     const InitiateUploadExistingFileOptions& options,
593     const InitiateUploadCallback& callback) {
594   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
595   DCHECK(!callback.is_null());
596 
597   InitiateUploadExistingFileRequest* request =
598       new InitiateUploadExistingFileRequest(sender_.get(),
599                                             url_generator_,
600                                             content_type,
601                                             content_length,
602                                             resource_id,
603                                             options.etag,
604                                             callback);
605   request->set_parent_resource_id(options.parent_resource_id);
606   request->set_title(options.title);
607   request->set_modified_date(options.modified_date);
608   request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
609   return sender_->StartRequestWithRetry(request);
610 }
611 
ResumeUpload(const GURL & upload_url,int64 start_position,int64 end_position,int64 content_length,const std::string & content_type,const base::FilePath & local_file_path,const UploadRangeCallback & callback,const ProgressCallback & progress_callback)612 CancelCallback DriveAPIService::ResumeUpload(
613     const GURL& upload_url,
614     int64 start_position,
615     int64 end_position,
616     int64 content_length,
617     const std::string& content_type,
618     const base::FilePath& local_file_path,
619     const UploadRangeCallback& callback,
620     const ProgressCallback& progress_callback) {
621   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
622   DCHECK(!callback.is_null());
623 
624   return sender_->StartRequestWithRetry(
625       new ResumeUploadRequest(
626           sender_.get(),
627           upload_url,
628           start_position,
629           end_position,
630           content_length,
631           content_type,
632           local_file_path,
633           callback,
634           progress_callback));
635 }
636 
GetUploadStatus(const GURL & upload_url,int64 content_length,const UploadRangeCallback & callback)637 CancelCallback DriveAPIService::GetUploadStatus(
638     const GURL& upload_url,
639     int64 content_length,
640     const UploadRangeCallback& callback) {
641   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
642   DCHECK(!callback.is_null());
643 
644   return sender_->StartRequestWithRetry(new GetUploadStatusRequest(
645       sender_.get(),
646       upload_url,
647       content_length,
648       callback));
649 }
650 
AuthorizeApp(const std::string & resource_id,const std::string & app_id,const AuthorizeAppCallback & callback)651 CancelCallback DriveAPIService::AuthorizeApp(
652     const std::string& resource_id,
653     const std::string& app_id,
654     const AuthorizeAppCallback& callback) {
655   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
656   DCHECK(!callback.is_null());
657 
658   // Files.Authorize is only available for whitelisted clients like official
659   // Google Chrome. In other cases, we fall back to Files.Get that returns the
660   // same value as Files.Authorize without doing authorization. In that case,
661   // the app can open if it was authorized by other means (from whitelisted
662   // clients or drive.google.com web UI.)
663   if (google_apis::IsGoogleChromeAPIKeyUsed()) {
664     google_apis::drive::FilesAuthorizeRequest* request =
665         new google_apis::drive::FilesAuthorizeRequest(
666             sender_.get(), url_generator_,
667             base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
668     request->set_app_id(app_id);
669     request->set_file_id(resource_id);
670     request->set_fields(kFileResourceOpenWithLinksFields);
671     return sender_->StartRequestWithRetry(request);
672   } else {
673     FilesGetRequest* request = new FilesGetRequest(
674         sender_.get(), url_generator_,
675         base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
676     request->set_file_id(resource_id);
677     request->set_fields(kFileResourceOpenWithLinksFields);
678     return sender_->StartRequestWithRetry(request);
679   }
680 }
681 
UninstallApp(const std::string & app_id,const google_apis::EntryActionCallback & callback)682 CancelCallback DriveAPIService::UninstallApp(
683     const std::string& app_id,
684     const google_apis::EntryActionCallback& callback) {
685   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
686   DCHECK(!callback.is_null());
687 
688   google_apis::drive::AppsDeleteRequest* request =
689       new google_apis::drive::AppsDeleteRequest(sender_.get(), url_generator_,
690                                                 callback);
691   request->set_app_id(app_id);
692   return sender_->StartRequestWithRetry(request);
693 }
694 
AddPermission(const std::string & resource_id,const std::string & email,google_apis::drive::PermissionRole role,const google_apis::EntryActionCallback & callback)695 google_apis::CancelCallback DriveAPIService::AddPermission(
696     const std::string& resource_id,
697     const std::string& email,
698     google_apis::drive::PermissionRole role,
699     const google_apis::EntryActionCallback& callback) {
700   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
701   DCHECK(!callback.is_null());
702 
703   google_apis::drive::PermissionsInsertRequest* request =
704       new google_apis::drive::PermissionsInsertRequest(sender_.get(),
705                                                        url_generator_,
706                                                        callback);
707   request->set_id(resource_id);
708   request->set_role(role);
709   request->set_type(google_apis::drive::PERMISSION_TYPE_USER);
710   request->set_value(email);
711   return sender_->StartRequestWithRetry(request);
712 }
713 
HasAccessToken() const714 bool DriveAPIService::HasAccessToken() const {
715   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
716   return sender_->auth_service()->HasAccessToken();
717 }
718 
RequestAccessToken(const AuthStatusCallback & callback)719 void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) {
720   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
721   DCHECK(!callback.is_null());
722 
723   const std::string access_token = sender_->auth_service()->access_token();
724   if (!access_token.empty()) {
725     callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
726     return;
727   }
728 
729   // Retrieve the new auth token.
730   sender_->auth_service()->StartAuthentication(callback);
731 }
732 
HasRefreshToken() const733 bool DriveAPIService::HasRefreshToken() const {
734   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735   return sender_->auth_service()->HasRefreshToken();
736 }
737 
ClearAccessToken()738 void DriveAPIService::ClearAccessToken() {
739   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
740   sender_->auth_service()->ClearAccessToken();
741 }
742 
ClearRefreshToken()743 void DriveAPIService::ClearRefreshToken() {
744   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
745   sender_->auth_service()->ClearRefreshToken();
746 }
747 
OnOAuth2RefreshTokenChanged()748 void DriveAPIService::OnOAuth2RefreshTokenChanged() {
749   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
750   if (CanSendRequest()) {
751     FOR_EACH_OBSERVER(
752         DriveServiceObserver, observers_, OnReadyToSendRequests());
753   } else if (!HasRefreshToken()) {
754     FOR_EACH_OBSERVER(
755         DriveServiceObserver, observers_, OnRefreshTokenInvalid());
756   }
757 }
758 
759 }  // namespace drive
760