OLD | NEW |
| (Empty) |
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/strings/stringprintf.h" | |
12 #include "chrome/browser/drive/drive_api_util.h" | |
13 #include "google_apis/drive/auth_service.h" | |
14 #include "google_apis/drive/base_requests.h" | |
15 #include "google_apis/drive/drive_api_parser.h" | |
16 #include "google_apis/drive/drive_api_requests.h" | |
17 #include "google_apis/drive/files_list_request_runner.h" | |
18 #include "google_apis/drive/request_sender.h" | |
19 #include "google_apis/google_api_keys.h" | |
20 #include "net/url_request/url_request_context_getter.h" | |
21 | |
22 using google_apis::AboutResourceCallback; | |
23 using google_apis::AppList; | |
24 using google_apis::AppListCallback; | |
25 using google_apis::AuthStatusCallback; | |
26 using google_apis::AuthorizeAppCallback; | |
27 using google_apis::CancelCallback; | |
28 using google_apis::ChangeList; | |
29 using google_apis::ChangeListCallback; | |
30 using google_apis::DownloadActionCallback; | |
31 using google_apis::EntryActionCallback; | |
32 using google_apis::FileList; | |
33 using google_apis::FileListCallback; | |
34 using google_apis::FileResource; | |
35 using google_apis::FileResourceCallback; | |
36 using google_apis::DRIVE_OTHER_ERROR; | |
37 using google_apis::DRIVE_PARSE_ERROR; | |
38 using google_apis::DriveApiErrorCode; | |
39 using google_apis::GetContentCallback; | |
40 using google_apis::GetShareUrlCallback; | |
41 using google_apis::HTTP_NOT_IMPLEMENTED; | |
42 using google_apis::HTTP_SUCCESS; | |
43 using google_apis::InitiateUploadCallback; | |
44 using google_apis::ProgressCallback; | |
45 using google_apis::RequestSender; | |
46 using google_apis::FilesListRequestRunner; | |
47 using google_apis::UploadRangeResponse; | |
48 using google_apis::drive::AboutGetRequest; | |
49 using google_apis::drive::AppsListRequest; | |
50 using google_apis::drive::ChangesListRequest; | |
51 using google_apis::drive::ChangesListNextPageRequest; | |
52 using google_apis::drive::ChildrenDeleteRequest; | |
53 using google_apis::drive::ChildrenInsertRequest; | |
54 using google_apis::drive::DownloadFileRequest; | |
55 using google_apis::drive::FilesCopyRequest; | |
56 using google_apis::drive::FilesGetRequest; | |
57 using google_apis::drive::FilesInsertRequest; | |
58 using google_apis::drive::FilesPatchRequest; | |
59 using google_apis::drive::FilesListRequest; | |
60 using google_apis::drive::FilesListNextPageRequest; | |
61 using google_apis::drive::FilesDeleteRequest; | |
62 using google_apis::drive::FilesTrashRequest; | |
63 using google_apis::drive::GetUploadStatusRequest; | |
64 using google_apis::drive::InitiateUploadExistingFileRequest; | |
65 using google_apis::drive::InitiateUploadNewFileRequest; | |
66 using google_apis::drive::ResumeUploadRequest; | |
67 using google_apis::drive::UploadRangeCallback; | |
68 | |
69 namespace drive { | |
70 | |
71 namespace { | |
72 | |
73 // OAuth2 scopes for Drive API. | |
74 const char kDriveScope[] = "https://www.googleapis.com/auth/drive"; | |
75 const char kDriveAppsReadonlyScope[] = | |
76 "https://www.googleapis.com/auth/drive.apps.readonly"; | |
77 const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps"; | |
78 const char kDocsListScope[] = "https://docs.google.com/feeds/"; | |
79 | |
80 // Mime type to create a directory. | |
81 const char kFolderMimeType[] = "application/vnd.google-apps.folder"; | |
82 | |
83 // Max number of file entries to be fetched in a single http request. | |
84 // | |
85 // The larger the number is, | |
86 // - The total running time to fetch the whole file list will become shorter. | |
87 // - The running time for a single request tends to become longer. | |
88 // Since the file list fetching is a completely background task, for our side, | |
89 // only the total time matters. However, the server seems to have a time limit | |
90 // per single request, which disables us to set the largest value (1000). | |
91 // TODO(kinaba): make it larger when the server gets faster. | |
92 const int kMaxNumFilesResourcePerRequest = 300; | |
93 const int kMaxNumFilesResourcePerRequestForSearch = 100; | |
94 | |
95 // For performance, we declare all fields we use. | |
96 const char kAboutResourceFields[] = | |
97 "kind,quotaBytesTotal,quotaBytesUsedAggregate,largestChangeId,rootFolderId"; | |
98 const char kFileResourceFields[] = | |
99 "kind,id,title,createdDate,sharedWithMeDate,mimeType," | |
100 "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
101 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
102 "parents(id,parentLink),alternateLink," | |
103 "modifiedDate,lastViewedByMeDate,shared"; | |
104 const char kFileResourceOpenWithLinksFields[] = | |
105 "kind,id,openWithLinks/*"; | |
106 const char kFileResourceShareLinkFields[] = | |
107 "kind,id,shareLink"; | |
108 const char kFileListFields[] = | |
109 "kind,items(kind,id,title,createdDate,sharedWithMeDate," | |
110 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
111 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
112 "parents(id,parentLink),alternateLink," | |
113 "modifiedDate,lastViewedByMeDate,shared),nextLink"; | |
114 const char kChangeListFields[] = | |
115 "kind,items(file(kind,id,title,createdDate,sharedWithMeDate," | |
116 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
117 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
118 "parents(id,parentLink),alternateLink,modifiedDate," | |
119 "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink," | |
120 "largestChangeId"; | |
121 | |
122 void ExtractOpenUrlAndRun(const std::string& app_id, | |
123 const AuthorizeAppCallback& callback, | |
124 DriveApiErrorCode error, | |
125 scoped_ptr<FileResource> value) { | |
126 DCHECK(!callback.is_null()); | |
127 | |
128 if (!value) { | |
129 callback.Run(error, GURL()); | |
130 return; | |
131 } | |
132 | |
133 const std::vector<FileResource::OpenWithLink>& open_with_links = | |
134 value->open_with_links(); | |
135 for (size_t i = 0; i < open_with_links.size(); ++i) { | |
136 if (open_with_links[i].app_id == app_id) { | |
137 callback.Run(HTTP_SUCCESS, open_with_links[i].open_url); | |
138 return; | |
139 } | |
140 } | |
141 | |
142 // Not found. | |
143 callback.Run(DRIVE_OTHER_ERROR, GURL()); | |
144 } | |
145 | |
146 void ExtractShareUrlAndRun(const GetShareUrlCallback& callback, | |
147 DriveApiErrorCode error, | |
148 scoped_ptr<FileResource> value) { | |
149 callback.Run(error, value ? value->share_link() : GURL()); | |
150 } | |
151 | |
152 // Ignores the |entry|, and runs the |callback|. | |
153 void EntryActionCallbackAdapter( | |
154 const EntryActionCallback& callback, | |
155 DriveApiErrorCode error, scoped_ptr<FileResource> entry) { | |
156 callback.Run(error); | |
157 } | |
158 | |
159 // The resource ID for the root directory for Drive API is defined in the spec: | |
160 // https://developers.google.com/drive/folder | |
161 const char kDriveApiRootDirectoryResourceId[] = "root"; | |
162 | |
163 } // namespace | |
164 | |
165 BatchRequestConfigurator::BatchRequestConfigurator( | |
166 const base::WeakPtr<google_apis::drive::BatchUploadRequest>& batch_request, | |
167 base::SequencedTaskRunner* task_runner, | |
168 const google_apis::DriveApiUrlGenerator& url_generator, | |
169 const google_apis::CancelCallback& cancel_callback) | |
170 : batch_request_(batch_request), | |
171 task_runner_(task_runner), | |
172 url_generator_(url_generator), | |
173 cancel_callback_(cancel_callback) { | |
174 } | |
175 | |
176 BatchRequestConfigurator::~BatchRequestConfigurator() { | |
177 // The batch requst has not been committed. | |
178 if (batch_request_) | |
179 cancel_callback_.Run(); | |
180 } | |
181 | |
182 google_apis::CancelCallback BatchRequestConfigurator::MultipartUploadNewFile( | |
183 const std::string& content_type, | |
184 int64 content_length, | |
185 const std::string& parent_resource_id, | |
186 const std::string& title, | |
187 const base::FilePath& local_file_path, | |
188 const UploadNewFileOptions& options, | |
189 const google_apis::FileResourceCallback& callback, | |
190 const google_apis::ProgressCallback& progress_callback) { | |
191 DCHECK(CalledOnValidThread()); | |
192 DCHECK(!callback.is_null()); | |
193 | |
194 scoped_ptr<google_apis::BatchableDelegate> delegate( | |
195 new google_apis::drive::MultipartUploadNewFileDelegate( | |
196 task_runner_.get(), title, parent_resource_id, content_type, | |
197 content_length, options.modified_date, options.last_viewed_by_me_date, | |
198 local_file_path, options.properties, url_generator_, callback, | |
199 progress_callback)); | |
200 // Batch request can be null when pre-authorization for the requst is failed | |
201 // in request sender. | |
202 if (batch_request_) | |
203 batch_request_->AddRequest(delegate.release()); | |
204 else | |
205 delegate->NotifyError(DRIVE_OTHER_ERROR); | |
206 return cancel_callback_; | |
207 } | |
208 | |
209 google_apis::CancelCallback | |
210 BatchRequestConfigurator::MultipartUploadExistingFile( | |
211 const std::string& content_type, | |
212 int64 content_length, | |
213 const std::string& resource_id, | |
214 const base::FilePath& local_file_path, | |
215 const UploadExistingFileOptions& options, | |
216 const google_apis::FileResourceCallback& callback, | |
217 const google_apis::ProgressCallback& progress_callback) { | |
218 DCHECK(CalledOnValidThread()); | |
219 DCHECK(!callback.is_null()); | |
220 | |
221 scoped_ptr<google_apis::BatchableDelegate> delegate( | |
222 new google_apis::drive::MultipartUploadExistingFileDelegate( | |
223 task_runner_.get(), options.title, resource_id, | |
224 options.parent_resource_id, content_type, content_length, | |
225 options.modified_date, options.last_viewed_by_me_date, | |
226 local_file_path, options.etag, options.properties, url_generator_, | |
227 callback, progress_callback)); | |
228 // Batch request can be null when pre-authorization for the requst is failed | |
229 // in request sender. | |
230 if (batch_request_) | |
231 batch_request_->AddRequest(delegate.release()); | |
232 else | |
233 delegate->NotifyError(DRIVE_OTHER_ERROR); | |
234 return cancel_callback_; | |
235 } | |
236 | |
237 void BatchRequestConfigurator::Commit() { | |
238 DCHECK(CalledOnValidThread()); | |
239 if (!batch_request_) | |
240 return; | |
241 batch_request_->Commit(); | |
242 batch_request_.reset(); | |
243 } | |
244 | |
245 DriveAPIService::DriveAPIService( | |
246 OAuth2TokenService* oauth2_token_service, | |
247 net::URLRequestContextGetter* url_request_context_getter, | |
248 base::SequencedTaskRunner* blocking_task_runner, | |
249 const GURL& base_url, | |
250 const GURL& base_download_url, | |
251 const std::string& custom_user_agent) | |
252 : oauth2_token_service_(oauth2_token_service), | |
253 url_request_context_getter_(url_request_context_getter), | |
254 blocking_task_runner_(blocking_task_runner), | |
255 url_generator_(base_url, base_download_url), | |
256 custom_user_agent_(custom_user_agent) { | |
257 } | |
258 | |
259 DriveAPIService::~DriveAPIService() { | |
260 DCHECK(thread_checker_.CalledOnValidThread()); | |
261 if (sender_.get()) | |
262 sender_->auth_service()->RemoveObserver(this); | |
263 } | |
264 | |
265 void DriveAPIService::Initialize(const std::string& account_id) { | |
266 DCHECK(thread_checker_.CalledOnValidThread()); | |
267 | |
268 std::vector<std::string> scopes; | |
269 scopes.push_back(kDriveScope); | |
270 scopes.push_back(kDriveAppsReadonlyScope); | |
271 scopes.push_back(kDriveAppsScope); | |
272 | |
273 // Note: The following scope is used to support GetShareUrl on Drive API v2. | |
274 // Unfortunately, there is no support on Drive API v2, so we need to fall back | |
275 // to GData WAPI for the GetShareUrl. | |
276 scopes.push_back(kDocsListScope); | |
277 | |
278 sender_.reset(new RequestSender( | |
279 new google_apis::AuthService(oauth2_token_service_, | |
280 account_id, | |
281 url_request_context_getter_.get(), | |
282 scopes), | |
283 url_request_context_getter_.get(), | |
284 blocking_task_runner_.get(), | |
285 custom_user_agent_)); | |
286 sender_->auth_service()->AddObserver(this); | |
287 | |
288 files_list_request_runner_.reset( | |
289 new FilesListRequestRunner(sender_.get(), url_generator_)); | |
290 } | |
291 | |
292 void DriveAPIService::AddObserver(DriveServiceObserver* observer) { | |
293 observers_.AddObserver(observer); | |
294 } | |
295 | |
296 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) { | |
297 observers_.RemoveObserver(observer); | |
298 } | |
299 | |
300 bool DriveAPIService::CanSendRequest() const { | |
301 DCHECK(thread_checker_.CalledOnValidThread()); | |
302 | |
303 return HasRefreshToken(); | |
304 } | |
305 | |
306 std::string DriveAPIService::GetRootResourceId() const { | |
307 return kDriveApiRootDirectoryResourceId; | |
308 } | |
309 | |
310 CancelCallback DriveAPIService::GetAllFileList( | |
311 const FileListCallback& callback) { | |
312 DCHECK(thread_checker_.CalledOnValidThread()); | |
313 DCHECK(!callback.is_null()); | |
314 | |
315 FilesListRequest* request = new FilesListRequest( | |
316 sender_.get(), url_generator_, callback); | |
317 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
318 request->set_q("trashed = false"); // Exclude trashed files. | |
319 request->set_fields(kFileListFields); | |
320 return sender_->StartRequestWithAuthRetry(request); | |
321 } | |
322 | |
323 CancelCallback DriveAPIService::GetFileListInDirectory( | |
324 const std::string& directory_resource_id, | |
325 const FileListCallback& callback) { | |
326 DCHECK(thread_checker_.CalledOnValidThread()); | |
327 DCHECK(!directory_resource_id.empty()); | |
328 DCHECK(!callback.is_null()); | |
329 | |
330 // Because children.list method on Drive API v2 returns only the list of | |
331 // children's references, but we need all file resource list. | |
332 // So, here we use files.list method instead, with setting parents query. | |
333 // After the migration from GData WAPI to Drive API v2, we should clean the | |
334 // code up by moving the responsibility to include "parents" in the query | |
335 // to client side. | |
336 // We aren't interested in files in trash in this context, neither. | |
337 return files_list_request_runner_->CreateAndStartWithSizeBackoff( | |
338 kMaxNumFilesResourcePerRequest, | |
339 base::StringPrintf( | |
340 "'%s' in parents and trashed = false", | |
341 util::EscapeQueryStringValue(directory_resource_id).c_str()), | |
342 kFileListFields, callback); | |
343 } | |
344 | |
345 CancelCallback DriveAPIService::Search( | |
346 const std::string& search_query, | |
347 const FileListCallback& callback) { | |
348 DCHECK(thread_checker_.CalledOnValidThread()); | |
349 DCHECK(!search_query.empty()); | |
350 DCHECK(!callback.is_null()); | |
351 | |
352 return files_list_request_runner_->CreateAndStartWithSizeBackoff( | |
353 kMaxNumFilesResourcePerRequestForSearch, | |
354 util::TranslateQuery(search_query), kFileListFields, callback); | |
355 } | |
356 | |
357 CancelCallback DriveAPIService::SearchByTitle( | |
358 const std::string& title, | |
359 const std::string& directory_resource_id, | |
360 const FileListCallback& callback) { | |
361 DCHECK(thread_checker_.CalledOnValidThread()); | |
362 DCHECK(!title.empty()); | |
363 DCHECK(!callback.is_null()); | |
364 | |
365 std::string query; | |
366 base::StringAppendF(&query, "title = '%s'", | |
367 util::EscapeQueryStringValue(title).c_str()); | |
368 if (!directory_resource_id.empty()) { | |
369 base::StringAppendF( | |
370 &query, " and '%s' in parents", | |
371 util::EscapeQueryStringValue(directory_resource_id).c_str()); | |
372 } | |
373 query += " and trashed = false"; | |
374 | |
375 FilesListRequest* request = new FilesListRequest( | |
376 sender_.get(), url_generator_, callback); | |
377 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
378 request->set_q(query); | |
379 request->set_fields(kFileListFields); | |
380 return sender_->StartRequestWithAuthRetry(request); | |
381 } | |
382 | |
383 CancelCallback DriveAPIService::GetChangeList( | |
384 int64 start_changestamp, | |
385 const ChangeListCallback& callback) { | |
386 DCHECK(thread_checker_.CalledOnValidThread()); | |
387 DCHECK(!callback.is_null()); | |
388 | |
389 ChangesListRequest* request = new ChangesListRequest( | |
390 sender_.get(), url_generator_, callback); | |
391 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
392 request->set_start_change_id(start_changestamp); | |
393 request->set_fields(kChangeListFields); | |
394 return sender_->StartRequestWithAuthRetry(request); | |
395 } | |
396 | |
397 CancelCallback DriveAPIService::GetRemainingChangeList( | |
398 const GURL& next_link, | |
399 const ChangeListCallback& callback) { | |
400 DCHECK(thread_checker_.CalledOnValidThread()); | |
401 DCHECK(!next_link.is_empty()); | |
402 DCHECK(!callback.is_null()); | |
403 | |
404 ChangesListNextPageRequest* request = new ChangesListNextPageRequest( | |
405 sender_.get(), callback); | |
406 request->set_next_link(next_link); | |
407 request->set_fields(kChangeListFields); | |
408 return sender_->StartRequestWithAuthRetry(request); | |
409 } | |
410 | |
411 CancelCallback DriveAPIService::GetRemainingFileList( | |
412 const GURL& next_link, | |
413 const FileListCallback& callback) { | |
414 DCHECK(thread_checker_.CalledOnValidThread()); | |
415 DCHECK(!next_link.is_empty()); | |
416 DCHECK(!callback.is_null()); | |
417 | |
418 FilesListNextPageRequest* request = new FilesListNextPageRequest( | |
419 sender_.get(), callback); | |
420 request->set_next_link(next_link); | |
421 request->set_fields(kFileListFields); | |
422 return sender_->StartRequestWithAuthRetry(request); | |
423 } | |
424 | |
425 CancelCallback DriveAPIService::GetFileResource( | |
426 const std::string& resource_id, | |
427 const FileResourceCallback& callback) { | |
428 DCHECK(thread_checker_.CalledOnValidThread()); | |
429 DCHECK(!callback.is_null()); | |
430 | |
431 FilesGetRequest* request = new FilesGetRequest( | |
432 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
433 callback); | |
434 request->set_file_id(resource_id); | |
435 request->set_fields(kFileResourceFields); | |
436 return sender_->StartRequestWithAuthRetry(request); | |
437 } | |
438 | |
439 CancelCallback DriveAPIService::GetShareUrl( | |
440 const std::string& resource_id, | |
441 const GURL& embed_origin, | |
442 const GetShareUrlCallback& callback) { | |
443 DCHECK(thread_checker_.CalledOnValidThread()); | |
444 DCHECK(!callback.is_null()); | |
445 | |
446 if (!google_apis::IsGoogleChromeAPIKeyUsed()) { | |
447 LOG(ERROR) << "Only the official build of Chrome OS can open share dialogs " | |
448 << "from the file manager."; | |
449 } | |
450 | |
451 FilesGetRequest* request = new FilesGetRequest( | |
452 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
453 base::Bind(&ExtractShareUrlAndRun, callback)); | |
454 request->set_file_id(resource_id); | |
455 request->set_fields(kFileResourceShareLinkFields); | |
456 request->set_embed_origin(embed_origin); | |
457 return sender_->StartRequestWithAuthRetry(request); | |
458 } | |
459 | |
460 CancelCallback DriveAPIService::GetAboutResource( | |
461 const AboutResourceCallback& callback) { | |
462 DCHECK(thread_checker_.CalledOnValidThread()); | |
463 DCHECK(!callback.is_null()); | |
464 | |
465 AboutGetRequest* request = | |
466 new AboutGetRequest(sender_.get(), url_generator_, callback); | |
467 request->set_fields(kAboutResourceFields); | |
468 return sender_->StartRequestWithAuthRetry(request); | |
469 } | |
470 | |
471 CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) { | |
472 DCHECK(thread_checker_.CalledOnValidThread()); | |
473 DCHECK(!callback.is_null()); | |
474 | |
475 return sender_->StartRequestWithAuthRetry( | |
476 new AppsListRequest(sender_.get(), url_generator_, | |
477 google_apis::IsGoogleChromeAPIKeyUsed(), callback)); | |
478 } | |
479 | |
480 CancelCallback DriveAPIService::DownloadFile( | |
481 const base::FilePath& local_cache_path, | |
482 const std::string& resource_id, | |
483 const DownloadActionCallback& download_action_callback, | |
484 const GetContentCallback& get_content_callback, | |
485 const ProgressCallback& progress_callback) { | |
486 DCHECK(thread_checker_.CalledOnValidThread()); | |
487 DCHECK(!download_action_callback.is_null()); | |
488 // get_content_callback may be null. | |
489 | |
490 return sender_->StartRequestWithAuthRetry(new DownloadFileRequest( | |
491 sender_.get(), url_generator_, resource_id, local_cache_path, | |
492 download_action_callback, get_content_callback, progress_callback)); | |
493 } | |
494 | |
495 CancelCallback DriveAPIService::DeleteResource( | |
496 const std::string& resource_id, | |
497 const std::string& etag, | |
498 const EntryActionCallback& callback) { | |
499 DCHECK(thread_checker_.CalledOnValidThread()); | |
500 DCHECK(!callback.is_null()); | |
501 | |
502 FilesDeleteRequest* request = new FilesDeleteRequest( | |
503 sender_.get(), url_generator_, callback); | |
504 request->set_file_id(resource_id); | |
505 request->set_etag(etag); | |
506 return sender_->StartRequestWithAuthRetry(request); | |
507 } | |
508 | |
509 CancelCallback DriveAPIService::TrashResource( | |
510 const std::string& resource_id, | |
511 const EntryActionCallback& callback) { | |
512 DCHECK(thread_checker_.CalledOnValidThread()); | |
513 DCHECK(!callback.is_null()); | |
514 | |
515 FilesTrashRequest* request = new FilesTrashRequest( | |
516 sender_.get(), url_generator_, | |
517 base::Bind(&EntryActionCallbackAdapter, callback)); | |
518 request->set_file_id(resource_id); | |
519 request->set_fields(kFileResourceFields); | |
520 return sender_->StartRequestWithAuthRetry(request); | |
521 } | |
522 | |
523 CancelCallback DriveAPIService::AddNewDirectory( | |
524 const std::string& parent_resource_id, | |
525 const std::string& directory_title, | |
526 const AddNewDirectoryOptions& options, | |
527 const FileResourceCallback& callback) { | |
528 DCHECK(thread_checker_.CalledOnValidThread()); | |
529 DCHECK(!callback.is_null()); | |
530 | |
531 FilesInsertRequest* request = new FilesInsertRequest( | |
532 sender_.get(), url_generator_, callback); | |
533 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
534 request->set_mime_type(kFolderMimeType); | |
535 request->set_modified_date(options.modified_date); | |
536 request->add_parent(parent_resource_id); | |
537 request->set_title(directory_title); | |
538 request->set_properties(options.properties); | |
539 request->set_fields(kFileResourceFields); | |
540 return sender_->StartRequestWithAuthRetry(request); | |
541 } | |
542 | |
543 CancelCallback DriveAPIService::CopyResource( | |
544 const std::string& resource_id, | |
545 const std::string& parent_resource_id, | |
546 const std::string& new_title, | |
547 const base::Time& last_modified, | |
548 const FileResourceCallback& callback) { | |
549 DCHECK(thread_checker_.CalledOnValidThread()); | |
550 DCHECK(!callback.is_null()); | |
551 | |
552 FilesCopyRequest* request = new FilesCopyRequest( | |
553 sender_.get(), url_generator_, callback); | |
554 request->set_file_id(resource_id); | |
555 request->add_parent(parent_resource_id); | |
556 request->set_title(new_title); | |
557 request->set_modified_date(last_modified); | |
558 request->set_fields(kFileResourceFields); | |
559 return sender_->StartRequestWithAuthRetry(request); | |
560 } | |
561 | |
562 CancelCallback DriveAPIService::UpdateResource( | |
563 const std::string& resource_id, | |
564 const std::string& parent_resource_id, | |
565 const std::string& new_title, | |
566 const base::Time& last_modified, | |
567 const base::Time& last_viewed_by_me, | |
568 const google_apis::drive::Properties& properties, | |
569 const FileResourceCallback& callback) { | |
570 DCHECK(thread_checker_.CalledOnValidThread()); | |
571 DCHECK(!callback.is_null()); | |
572 | |
573 FilesPatchRequest* request = new FilesPatchRequest( | |
574 sender_.get(), url_generator_, callback); | |
575 request->set_file_id(resource_id); | |
576 request->set_title(new_title); | |
577 if (!parent_resource_id.empty()) | |
578 request->add_parent(parent_resource_id); | |
579 if (!last_modified.is_null()) { | |
580 // Need to set setModifiedDate to true to overwrite modifiedDate. | |
581 request->set_set_modified_date(true); | |
582 request->set_modified_date(last_modified); | |
583 } | |
584 if (!last_viewed_by_me.is_null()) { | |
585 // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate | |
586 // will be set to the request time (not the specified time via request). | |
587 request->set_update_viewed_date(false); | |
588 request->set_last_viewed_by_me_date(last_viewed_by_me); | |
589 } | |
590 request->set_fields(kFileResourceFields); | |
591 request->set_properties(properties); | |
592 return sender_->StartRequestWithAuthRetry(request); | |
593 } | |
594 | |
595 CancelCallback DriveAPIService::AddResourceToDirectory( | |
596 const std::string& parent_resource_id, | |
597 const std::string& resource_id, | |
598 const EntryActionCallback& callback) { | |
599 DCHECK(thread_checker_.CalledOnValidThread()); | |
600 DCHECK(!callback.is_null()); | |
601 | |
602 ChildrenInsertRequest* request = | |
603 new ChildrenInsertRequest(sender_.get(), url_generator_, callback); | |
604 request->set_folder_id(parent_resource_id); | |
605 request->set_id(resource_id); | |
606 return sender_->StartRequestWithAuthRetry(request); | |
607 } | |
608 | |
609 CancelCallback DriveAPIService::RemoveResourceFromDirectory( | |
610 const std::string& parent_resource_id, | |
611 const std::string& resource_id, | |
612 const EntryActionCallback& callback) { | |
613 DCHECK(thread_checker_.CalledOnValidThread()); | |
614 DCHECK(!callback.is_null()); | |
615 | |
616 ChildrenDeleteRequest* request = | |
617 new ChildrenDeleteRequest(sender_.get(), url_generator_, callback); | |
618 request->set_child_id(resource_id); | |
619 request->set_folder_id(parent_resource_id); | |
620 return sender_->StartRequestWithAuthRetry(request); | |
621 } | |
622 | |
623 CancelCallback DriveAPIService::InitiateUploadNewFile( | |
624 const std::string& content_type, | |
625 int64 content_length, | |
626 const std::string& parent_resource_id, | |
627 const std::string& title, | |
628 const UploadNewFileOptions& options, | |
629 const InitiateUploadCallback& callback) { | |
630 DCHECK(thread_checker_.CalledOnValidThread()); | |
631 DCHECK(!callback.is_null()); | |
632 | |
633 InitiateUploadNewFileRequest* request = | |
634 new InitiateUploadNewFileRequest(sender_.get(), | |
635 url_generator_, | |
636 content_type, | |
637 content_length, | |
638 parent_resource_id, | |
639 title, | |
640 callback); | |
641 request->set_modified_date(options.modified_date); | |
642 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
643 request->set_properties(options.properties); | |
644 return sender_->StartRequestWithAuthRetry(request); | |
645 } | |
646 | |
647 CancelCallback DriveAPIService::InitiateUploadExistingFile( | |
648 const std::string& content_type, | |
649 int64 content_length, | |
650 const std::string& resource_id, | |
651 const UploadExistingFileOptions& options, | |
652 const InitiateUploadCallback& callback) { | |
653 DCHECK(thread_checker_.CalledOnValidThread()); | |
654 DCHECK(!callback.is_null()); | |
655 | |
656 InitiateUploadExistingFileRequest* request = | |
657 new InitiateUploadExistingFileRequest(sender_.get(), | |
658 url_generator_, | |
659 content_type, | |
660 content_length, | |
661 resource_id, | |
662 options.etag, | |
663 callback); | |
664 request->set_parent_resource_id(options.parent_resource_id); | |
665 request->set_title(options.title); | |
666 request->set_modified_date(options.modified_date); | |
667 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
668 request->set_properties(options.properties); | |
669 return sender_->StartRequestWithAuthRetry(request); | |
670 } | |
671 | |
672 CancelCallback DriveAPIService::ResumeUpload( | |
673 const GURL& upload_url, | |
674 int64 start_position, | |
675 int64 end_position, | |
676 int64 content_length, | |
677 const std::string& content_type, | |
678 const base::FilePath& local_file_path, | |
679 const UploadRangeCallback& callback, | |
680 const ProgressCallback& progress_callback) { | |
681 DCHECK(thread_checker_.CalledOnValidThread()); | |
682 DCHECK(!callback.is_null()); | |
683 | |
684 return sender_->StartRequestWithAuthRetry(new ResumeUploadRequest( | |
685 sender_.get(), upload_url, start_position, end_position, content_length, | |
686 content_type, local_file_path, callback, progress_callback)); | |
687 } | |
688 | |
689 CancelCallback DriveAPIService::GetUploadStatus( | |
690 const GURL& upload_url, | |
691 int64 content_length, | |
692 const UploadRangeCallback& callback) { | |
693 DCHECK(thread_checker_.CalledOnValidThread()); | |
694 DCHECK(!callback.is_null()); | |
695 | |
696 return sender_->StartRequestWithAuthRetry(new GetUploadStatusRequest( | |
697 sender_.get(), upload_url, content_length, callback)); | |
698 } | |
699 | |
700 CancelCallback DriveAPIService::MultipartUploadNewFile( | |
701 const std::string& content_type, | |
702 int64 content_length, | |
703 const std::string& parent_resource_id, | |
704 const std::string& title, | |
705 const base::FilePath& local_file_path, | |
706 const drive::UploadNewFileOptions& options, | |
707 const FileResourceCallback& callback, | |
708 const google_apis::ProgressCallback& progress_callback) { | |
709 DCHECK(thread_checker_.CalledOnValidThread()); | |
710 DCHECK(!callback.is_null()); | |
711 | |
712 return sender_->StartRequestWithAuthRetry( | |
713 new google_apis::drive::SingleBatchableDelegateRequest( | |
714 sender_.get(), | |
715 new google_apis::drive::MultipartUploadNewFileDelegate( | |
716 sender_->blocking_task_runner(), title, parent_resource_id, | |
717 content_type, content_length, options.modified_date, | |
718 options.last_viewed_by_me_date, local_file_path, | |
719 options.properties, url_generator_, callback, | |
720 progress_callback))); | |
721 } | |
722 | |
723 CancelCallback DriveAPIService::MultipartUploadExistingFile( | |
724 const std::string& content_type, | |
725 int64 content_length, | |
726 const std::string& resource_id, | |
727 const base::FilePath& local_file_path, | |
728 const drive::UploadExistingFileOptions& options, | |
729 const FileResourceCallback& callback, | |
730 const google_apis::ProgressCallback& progress_callback) { | |
731 DCHECK(thread_checker_.CalledOnValidThread()); | |
732 DCHECK(!callback.is_null()); | |
733 | |
734 return sender_->StartRequestWithAuthRetry( | |
735 new google_apis::drive::SingleBatchableDelegateRequest( | |
736 sender_.get(), | |
737 new google_apis::drive::MultipartUploadExistingFileDelegate( | |
738 sender_->blocking_task_runner(), options.title, resource_id, | |
739 options.parent_resource_id, content_type, content_length, | |
740 options.modified_date, options.last_viewed_by_me_date, | |
741 local_file_path, options.etag, options.properties, url_generator_, | |
742 callback, progress_callback))); | |
743 } | |
744 | |
745 CancelCallback DriveAPIService::AuthorizeApp( | |
746 const std::string& resource_id, | |
747 const std::string& app_id, | |
748 const AuthorizeAppCallback& callback) { | |
749 DCHECK(thread_checker_.CalledOnValidThread()); | |
750 DCHECK(!callback.is_null()); | |
751 | |
752 // Files.Authorize is only available for whitelisted clients like official | |
753 // Google Chrome. In other cases, we fall back to Files.Get that returns the | |
754 // same value as Files.Authorize without doing authorization. In that case, | |
755 // the app can open if it was authorized by other means (from whitelisted | |
756 // clients or drive.google.com web UI.) | |
757 if (google_apis::IsGoogleChromeAPIKeyUsed()) { | |
758 google_apis::drive::FilesAuthorizeRequest* request = | |
759 new google_apis::drive::FilesAuthorizeRequest( | |
760 sender_.get(), url_generator_, | |
761 base::Bind(&ExtractOpenUrlAndRun, app_id, callback)); | |
762 request->set_app_id(app_id); | |
763 request->set_file_id(resource_id); | |
764 request->set_fields(kFileResourceOpenWithLinksFields); | |
765 return sender_->StartRequestWithAuthRetry(request); | |
766 } else { | |
767 FilesGetRequest* request = new FilesGetRequest( | |
768 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
769 base::Bind(&ExtractOpenUrlAndRun, app_id, callback)); | |
770 request->set_file_id(resource_id); | |
771 request->set_fields(kFileResourceOpenWithLinksFields); | |
772 return sender_->StartRequestWithAuthRetry(request); | |
773 } | |
774 } | |
775 | |
776 CancelCallback DriveAPIService::UninstallApp( | |
777 const std::string& app_id, | |
778 const google_apis::EntryActionCallback& callback) { | |
779 DCHECK(thread_checker_.CalledOnValidThread()); | |
780 DCHECK(!callback.is_null()); | |
781 | |
782 google_apis::drive::AppsDeleteRequest* request = | |
783 new google_apis::drive::AppsDeleteRequest(sender_.get(), url_generator_, | |
784 callback); | |
785 request->set_app_id(app_id); | |
786 return sender_->StartRequestWithAuthRetry(request); | |
787 } | |
788 | |
789 google_apis::CancelCallback DriveAPIService::AddPermission( | |
790 const std::string& resource_id, | |
791 const std::string& email, | |
792 google_apis::drive::PermissionRole role, | |
793 const google_apis::EntryActionCallback& callback) { | |
794 DCHECK(thread_checker_.CalledOnValidThread()); | |
795 DCHECK(!callback.is_null()); | |
796 | |
797 google_apis::drive::PermissionsInsertRequest* request = | |
798 new google_apis::drive::PermissionsInsertRequest(sender_.get(), | |
799 url_generator_, | |
800 callback); | |
801 request->set_id(resource_id); | |
802 request->set_role(role); | |
803 request->set_type(google_apis::drive::PERMISSION_TYPE_USER); | |
804 request->set_value(email); | |
805 return sender_->StartRequestWithAuthRetry(request); | |
806 } | |
807 | |
808 bool DriveAPIService::HasAccessToken() const { | |
809 DCHECK(thread_checker_.CalledOnValidThread()); | |
810 return sender_->auth_service()->HasAccessToken(); | |
811 } | |
812 | |
813 void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) { | |
814 DCHECK(thread_checker_.CalledOnValidThread()); | |
815 DCHECK(!callback.is_null()); | |
816 | |
817 const std::string access_token = sender_->auth_service()->access_token(); | |
818 if (!access_token.empty()) { | |
819 callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token); | |
820 return; | |
821 } | |
822 | |
823 // Retrieve the new auth token. | |
824 sender_->auth_service()->StartAuthentication(callback); | |
825 } | |
826 | |
827 bool DriveAPIService::HasRefreshToken() const { | |
828 DCHECK(thread_checker_.CalledOnValidThread()); | |
829 return sender_->auth_service()->HasRefreshToken(); | |
830 } | |
831 | |
832 void DriveAPIService::ClearAccessToken() { | |
833 DCHECK(thread_checker_.CalledOnValidThread()); | |
834 sender_->auth_service()->ClearAccessToken(); | |
835 } | |
836 | |
837 void DriveAPIService::ClearRefreshToken() { | |
838 DCHECK(thread_checker_.CalledOnValidThread()); | |
839 sender_->auth_service()->ClearRefreshToken(); | |
840 } | |
841 | |
842 void DriveAPIService::OnOAuth2RefreshTokenChanged() { | |
843 DCHECK(thread_checker_.CalledOnValidThread()); | |
844 if (CanSendRequest()) { | |
845 FOR_EACH_OBSERVER( | |
846 DriveServiceObserver, observers_, OnReadyToSendRequests()); | |
847 } else if (!HasRefreshToken()) { | |
848 FOR_EACH_OBSERVER( | |
849 DriveServiceObserver, observers_, OnRefreshTokenInvalid()); | |
850 } | |
851 } | |
852 | |
853 scoped_ptr<BatchRequestConfiguratorInterface> | |
854 DriveAPIService::StartBatchRequest() { | |
855 scoped_ptr<google_apis::drive::BatchUploadRequest> request( | |
856 new google_apis::drive::BatchUploadRequest(sender_.get(), | |
857 url_generator_)); | |
858 const base::WeakPtr<google_apis::drive::BatchUploadRequest> weak_ref = | |
859 request->GetWeakPtrAsBatchUploadRequest(); | |
860 // Have sender_ manage the lifetime of the request. | |
861 // TODO(hirono): Currently we need to pass the ownership of the request to | |
862 // RequestSender before the request is committed because the request has a | |
863 // reference to RequestSender and we should ensure to delete the request when | |
864 // the sender is deleted. Resolve the circulating dependency and fix it. | |
865 const google_apis::CancelCallback callback = | |
866 sender_->StartRequestWithAuthRetry(request.release()); | |
867 return make_scoped_ptr<BatchRequestConfiguratorInterface>( | |
868 new BatchRequestConfigurator(weak_ref, sender_->blocking_task_runner(), | |
869 url_generator_, callback)); | |
870 } | |
871 | |
872 } // namespace drive | |
OLD | NEW |