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