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 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|. 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 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 180 DriveAPIService::~DriveAPIService() { 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 182 if (sender_.get()) 183 sender_->auth_service()->RemoveObserver(this); 184 } 185 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 208 void DriveAPIService::AddObserver(DriveServiceObserver* observer) { 209 observers_.AddObserver(observer); 210 } 211 212 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) { 213 observers_.RemoveObserver(observer); 214 } 215 216 bool DriveAPIService::CanSendRequest() const { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 218 219 return HasRefreshToken(); 220 } 221 222 ResourceIdCanonicalizer DriveAPIService::GetResourceIdCanonicalizer() const { 223 return base::Bind(&drive::util::CanonicalizeResourceId); 224 } 225 226 std::string DriveAPIService::GetRootResourceId() const { 227 return kDriveApiRootDirectoryResourceId; 228 } 229 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 714 bool DriveAPIService::HasAccessToken() const { 715 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 716 return sender_->auth_service()->HasAccessToken(); 717 } 718 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 733 bool DriveAPIService::HasRefreshToken() const { 734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 735 return sender_->auth_service()->HasRefreshToken(); 736 } 737 738 void DriveAPIService::ClearAccessToken() { 739 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 740 sender_->auth_service()->ClearAccessToken(); 741 } 742 743 void DriveAPIService::ClearRefreshToken() { 744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 745 sender_->auth_service()->ClearRefreshToken(); 746 } 747 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