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 "base/task_runner_util.h" 13#include "base/values.h" 14#include "chrome/browser/drive/drive_api_util.h" 15#include "chrome/browser/google_apis/auth_service.h" 16#include "chrome/browser/google_apis/drive_api_parser.h" 17#include "chrome/browser/google_apis/drive_api_requests.h" 18#include "chrome/browser/google_apis/gdata_errorcode.h" 19#include "chrome/browser/google_apis/gdata_wapi_parser.h" 20#include "chrome/browser/google_apis/gdata_wapi_requests.h" 21#include "chrome/browser/google_apis/request_sender.h" 22#include "content/public/browser/browser_thread.h" 23 24using content::BrowserThread; 25using google_apis::AppList; 26using google_apis::AuthStatusCallback; 27using google_apis::AuthorizeAppCallback; 28using google_apis::CancelCallback; 29using google_apis::ChangeList; 30using google_apis::DownloadActionCallback; 31using google_apis::EntryActionCallback; 32using google_apis::FileList; 33using google_apis::FileResource; 34using google_apis::GDATA_OTHER_ERROR; 35using google_apis::GDATA_PARSE_ERROR; 36using google_apis::GDataErrorCode; 37using google_apis::GetAboutRequest; 38using google_apis::GetAboutResourceCallback; 39using google_apis::GetAppListCallback; 40using google_apis::GetApplistRequest; 41using google_apis::GetChangelistRequest; 42using google_apis::GetContentCallback; 43using google_apis::GetFileRequest; 44using google_apis::GetFilelistRequest; 45using google_apis::GetResourceEntryCallback; 46using google_apis::GetResourceEntryRequest; 47using google_apis::GetResourceListCallback; 48using google_apis::GetShareUrlCallback; 49using google_apis::HTTP_NOT_IMPLEMENTED; 50using google_apis::HTTP_SUCCESS; 51using google_apis::InitiateUploadCallback; 52using google_apis::Link; 53using google_apis::ProgressCallback; 54using google_apis::RequestSender; 55using google_apis::ResourceEntry; 56using google_apis::ResourceList; 57using google_apis::UploadRangeCallback; 58using google_apis::UploadRangeResponse; 59using google_apis::drive::ContinueGetFileListRequest; 60using google_apis::drive::CopyResourceRequest; 61using google_apis::drive::CreateDirectoryRequest; 62using google_apis::drive::DeleteResourceRequest; 63using google_apis::drive::DownloadFileRequest; 64using google_apis::drive::GetUploadStatusRequest; 65using google_apis::drive::InitiateUploadExistingFileRequest; 66using google_apis::drive::InitiateUploadNewFileRequest; 67using google_apis::drive::InsertResourceRequest; 68using google_apis::drive::RenameResourceRequest; 69using google_apis::drive::ResumeUploadRequest; 70using google_apis::drive::TouchResourceRequest; 71using google_apis::drive::TrashResourceRequest; 72 73namespace drive { 74 75namespace { 76 77// OAuth2 scopes for Drive API. 78const char kDriveScope[] = "https://www.googleapis.com/auth/drive"; 79const char kDriveAppsReadonlyScope[] = 80 "https://www.googleapis.com/auth/drive.apps.readonly"; 81 82// Expected max number of files resources in a http request. 83// Be careful not to use something too small because it might overload the 84// server. Be careful not to use something too large because it takes longer 85// time to fetch the result without UI response. 86const int kMaxNumFilesResourcePerRequest = 500; 87const int kMaxNumFilesResourcePerRequestForSearch = 50; 88 89scoped_ptr<ResourceList> ParseChangeListJsonToResourceList( 90 scoped_ptr<base::Value> value) { 91 scoped_ptr<ChangeList> change_list(ChangeList::CreateFrom(*value)); 92 if (!change_list) { 93 return scoped_ptr<ResourceList>(); 94 } 95 96 return ResourceList::CreateFromChangeList(*change_list); 97} 98 99scoped_ptr<ResourceList> ParseFileListJsonToResourceList( 100 scoped_ptr<base::Value> value) { 101 scoped_ptr<FileList> file_list(FileList::CreateFrom(*value)); 102 if (!file_list) { 103 return scoped_ptr<ResourceList>(); 104 } 105 106 return ResourceList::CreateFromFileList(*file_list); 107} 108 109// Parses JSON value representing either ChangeList or FileList into 110// ResourceList. 111scoped_ptr<ResourceList> ParseResourceListOnBlockingPool( 112 scoped_ptr<base::Value> value) { 113 DCHECK(value); 114 115 // Dispatch the parsing based on kind field. 116 if (ChangeList::HasChangeListKind(*value)) { 117 return ParseChangeListJsonToResourceList(value.Pass()); 118 } 119 if (FileList::HasFileListKind(*value)) { 120 return ParseFileListJsonToResourceList(value.Pass()); 121 } 122 123 // The value type is unknown, so give up to parse and return an error. 124 return scoped_ptr<ResourceList>(); 125} 126 127// Callback invoked when the parsing of resource list is completed, 128// regardless whether it is succeeded or not. 129void DidParseResourceListOnBlockingPool( 130 const GetResourceListCallback& callback, 131 scoped_ptr<ResourceList> resource_list) { 132 GDataErrorCode error = resource_list ? HTTP_SUCCESS : GDATA_PARSE_ERROR; 133 callback.Run(error, resource_list.Pass()); 134} 135 136// Sends a task to parse the JSON value into ResourceList on blocking pool, 137// with a callback which is called when the task is done. 138void ParseResourceListOnBlockingPoolAndRun( 139 scoped_refptr<base::TaskRunner> blocking_task_runner, 140 const GetResourceListCallback& callback, 141 GDataErrorCode error, 142 scoped_ptr<base::Value> value) { 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 144 DCHECK(!callback.is_null()); 145 146 if (error != HTTP_SUCCESS) { 147 // An error occurs, so run callback immediately. 148 callback.Run(error, scoped_ptr<ResourceList>()); 149 return; 150 } 151 152 PostTaskAndReplyWithResult( 153 blocking_task_runner.get(), 154 FROM_HERE, 155 base::Bind(&ParseResourceListOnBlockingPool, base::Passed(&value)), 156 base::Bind(&DidParseResourceListOnBlockingPool, callback)); 157} 158 159// Parses the FileResource value to ResourceEntry and runs |callback| on the 160// UI thread. 161void ParseResourceEntryAndRun( 162 const GetResourceEntryCallback& callback, 163 GDataErrorCode error, 164 scoped_ptr<FileResource> value) { 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 166 DCHECK(!callback.is_null()); 167 168 if (!value) { 169 callback.Run(error, scoped_ptr<ResourceEntry>()); 170 return; 171 } 172 173 // Converting to ResourceEntry is cheap enough to do on UI thread. 174 scoped_ptr<ResourceEntry> entry = 175 ResourceEntry::CreateFromFileResource(*value); 176 if (!entry) { 177 callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>()); 178 return; 179 } 180 181 callback.Run(error, entry.Pass()); 182} 183 184// Parses the JSON value to AppList runs |callback| on the UI thread 185// once parsing is done. 186void ParseAppListAndRun(const google_apis::GetAppListCallback& callback, 187 google_apis::GDataErrorCode error, 188 scoped_ptr<base::Value> value) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 DCHECK(!callback.is_null()); 191 192 if (!value) { 193 callback.Run(error, scoped_ptr<google_apis::AppList>()); 194 return; 195 } 196 197 // Parsing AppList is cheap enough to do on UI thread. 198 scoped_ptr<google_apis::AppList> app_list = 199 google_apis::AppList::CreateFrom(*value); 200 if (!app_list) { 201 callback.Run(google_apis::GDATA_PARSE_ERROR, 202 scoped_ptr<google_apis::AppList>()); 203 return; 204 } 205 206 callback.Run(error, app_list.Pass()); 207} 208 209// Parses the FileResource value to ResourceEntry for upload range request, 210// and runs |callback| on the UI thread. 211void ParseResourceEntryForUploadRangeAndRun( 212 const UploadRangeCallback& callback, 213 const UploadRangeResponse& response, 214 scoped_ptr<FileResource> value) { 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 216 DCHECK(!callback.is_null()); 217 218 if (!value) { 219 callback.Run(response, scoped_ptr<ResourceEntry>()); 220 return; 221 } 222 223 // Converting to ResourceEntry is cheap enough to do on UI thread. 224 scoped_ptr<ResourceEntry> entry = 225 ResourceEntry::CreateFromFileResource(*value); 226 if (!entry) { 227 callback.Run(UploadRangeResponse(GDATA_PARSE_ERROR, 228 response.start_position_received, 229 response.end_position_received), 230 scoped_ptr<ResourceEntry>()); 231 return; 232 } 233 234 callback.Run(response, entry.Pass()); 235} 236 237void ExtractOpenUrlAndRun(const std::string& app_id, 238 const AuthorizeAppCallback& callback, 239 GDataErrorCode error, 240 scoped_ptr<FileResource> value) { 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 242 DCHECK(!callback.is_null()); 243 244 if (!value) { 245 callback.Run(error, GURL()); 246 return; 247 } 248 249 const std::vector<FileResource::OpenWithLink>& open_with_links = 250 value->open_with_links(); 251 for (size_t i = 0; i < open_with_links.size(); ++i) { 252 if (open_with_links[i].app_id == app_id) { 253 callback.Run(HTTP_SUCCESS, open_with_links[i].open_url); 254 return; 255 } 256 } 257 258 // Not found. 259 callback.Run(GDATA_OTHER_ERROR, GURL()); 260} 261 262// The resource ID for the root directory for Drive API is defined in the spec: 263// https://developers.google.com/drive/folder 264const char kDriveApiRootDirectoryResourceId[] = "root"; 265 266} // namespace 267 268DriveAPIService::DriveAPIService( 269 OAuth2TokenService* oauth2_token_service, 270 net::URLRequestContextGetter* url_request_context_getter, 271 base::TaskRunner* blocking_task_runner, 272 const GURL& base_url, 273 const GURL& base_download_url, 274 const GURL& wapi_base_url, 275 const std::string& custom_user_agent) 276 : oauth2_token_service_(oauth2_token_service), 277 url_request_context_getter_(url_request_context_getter), 278 blocking_task_runner_(blocking_task_runner), 279 url_generator_(base_url, base_download_url), 280 wapi_url_generator_(wapi_base_url, base_download_url), 281 custom_user_agent_(custom_user_agent) { 282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 283} 284 285DriveAPIService::~DriveAPIService() { 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 if (sender_.get()) 288 sender_->auth_service()->RemoveObserver(this); 289} 290 291void DriveAPIService::Initialize() { 292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 293 294 std::vector<std::string> scopes; 295 scopes.push_back(kDriveScope); 296 scopes.push_back(kDriveAppsReadonlyScope); 297 298 // GData WAPI token. These are for GetShareUrl(). 299 scopes.push_back(util::kDocsListScope); 300 scopes.push_back(util::kDriveAppsScope); 301 302 sender_.reset(new RequestSender( 303 new google_apis::AuthService( 304 oauth2_token_service_, url_request_context_getter_, scopes), 305 url_request_context_getter_, 306 blocking_task_runner_.get(), 307 custom_user_agent_)); 308 sender_->auth_service()->AddObserver(this); 309} 310 311void DriveAPIService::AddObserver(DriveServiceObserver* observer) { 312 observers_.AddObserver(observer); 313} 314 315void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) { 316 observers_.RemoveObserver(observer); 317} 318 319bool DriveAPIService::CanSendRequest() const { 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 321 322 return HasRefreshToken(); 323} 324 325std::string DriveAPIService::CanonicalizeResourceId( 326 const std::string& resource_id) const { 327 return drive::util::CanonicalizeResourceId(resource_id); 328} 329 330std::string DriveAPIService::GetRootResourceId() const { 331 return kDriveApiRootDirectoryResourceId; 332} 333 334CancelCallback DriveAPIService::GetAllResourceList( 335 const GetResourceListCallback& callback) { 336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 337 DCHECK(!callback.is_null()); 338 339 // The simplest way to fetch the all resources list looks files.list method, 340 // but it seems impossible to know the returned list's changestamp. 341 // Thus, instead, we use changes.list method with includeDeleted=false here. 342 // The returned list should contain only resources currently existing. 343 return sender_->StartRequestWithRetry( 344 new GetChangelistRequest( 345 sender_.get(), 346 url_generator_, 347 false, // include deleted 348 0, 349 kMaxNumFilesResourcePerRequest, 350 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 351 blocking_task_runner_, 352 callback))); 353} 354 355CancelCallback DriveAPIService::GetResourceListInDirectory( 356 const std::string& directory_resource_id, 357 const GetResourceListCallback& callback) { 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 359 DCHECK(!directory_resource_id.empty()); 360 DCHECK(!callback.is_null()); 361 362 // Because children.list method on Drive API v2 returns only the list of 363 // children's references, but we need all file resource list. 364 // So, here we use files.list method instead, with setting parents query. 365 // After the migration from GData WAPI to Drive API v2, we should clean the 366 // code up by moving the responsibility to include "parents" in the query 367 // to client side. 368 // We aren't interested in files in trash in this context, neither. 369 return sender_->StartRequestWithRetry( 370 new GetFilelistRequest( 371 sender_.get(), 372 url_generator_, 373 base::StringPrintf( 374 "'%s' in parents and trashed = false", 375 drive::util::EscapeQueryStringValue( 376 directory_resource_id).c_str()), 377 kMaxNumFilesResourcePerRequest, 378 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 379 blocking_task_runner_, 380 callback))); 381} 382 383CancelCallback DriveAPIService::Search( 384 const std::string& search_query, 385 const GetResourceListCallback& callback) { 386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 387 DCHECK(!search_query.empty()); 388 DCHECK(!callback.is_null()); 389 390 return sender_->StartRequestWithRetry( 391 new GetFilelistRequest( 392 sender_.get(), 393 url_generator_, 394 drive::util::TranslateQuery(search_query), 395 kMaxNumFilesResourcePerRequestForSearch, 396 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 397 blocking_task_runner_, 398 callback))); 399} 400 401CancelCallback DriveAPIService::SearchByTitle( 402 const std::string& title, 403 const std::string& directory_resource_id, 404 const GetResourceListCallback& callback) { 405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 406 DCHECK(!title.empty()); 407 DCHECK(!callback.is_null()); 408 409 std::string query; 410 base::StringAppendF(&query, "title = '%s'", 411 drive::util::EscapeQueryStringValue(title).c_str()); 412 if (!directory_resource_id.empty()) { 413 base::StringAppendF( 414 &query, " and '%s' in parents", 415 drive::util::EscapeQueryStringValue(directory_resource_id).c_str()); 416 } 417 query += " and trashed = false"; 418 419 return sender_->StartRequestWithRetry( 420 new GetFilelistRequest( 421 sender_.get(), 422 url_generator_, 423 query, 424 kMaxNumFilesResourcePerRequest, 425 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 426 blocking_task_runner_, 427 callback))); 428} 429 430CancelCallback DriveAPIService::GetChangeList( 431 int64 start_changestamp, 432 const GetResourceListCallback& callback) { 433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 434 DCHECK(!callback.is_null()); 435 436 return sender_->StartRequestWithRetry( 437 new GetChangelistRequest( 438 sender_.get(), 439 url_generator_, 440 true, // include deleted 441 start_changestamp, 442 kMaxNumFilesResourcePerRequest, 443 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 444 blocking_task_runner_, 445 callback))); 446} 447 448CancelCallback DriveAPIService::ContinueGetResourceList( 449 const GURL& override_url, 450 const GetResourceListCallback& callback) { 451 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 452 DCHECK(!callback.is_null()); 453 454 return sender_->StartRequestWithRetry( 455 new ContinueGetFileListRequest( 456 sender_.get(), 457 override_url, 458 base::Bind(&ParseResourceListOnBlockingPoolAndRun, 459 blocking_task_runner_, 460 callback))); 461} 462 463CancelCallback DriveAPIService::GetResourceEntry( 464 const std::string& resource_id, 465 const GetResourceEntryCallback& callback) { 466 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 467 DCHECK(!callback.is_null()); 468 469 return sender_->StartRequestWithRetry(new GetFileRequest( 470 sender_.get(), 471 url_generator_, 472 resource_id, 473 base::Bind(&ParseResourceEntryAndRun, callback))); 474} 475 476CancelCallback DriveAPIService::GetShareUrl( 477 const std::string& resource_id, 478 const GURL& embed_origin, 479 const GetShareUrlCallback& callback) { 480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 481 DCHECK(!callback.is_null()); 482 483 // Unfortunately "share url" is not yet supported on Drive API v2. 484 // So, as a fallback, we use GData WAPI protocol for this method. 485 // TODO(hidehiko): Get rid of this implementation when share url is 486 // supported on Drive API v2. 487 return sender_->StartRequestWithRetry( 488 new GetResourceEntryRequest(sender_.get(), 489 wapi_url_generator_, 490 resource_id, 491 embed_origin, 492 base::Bind(&util::ParseShareUrlAndRun, 493 callback))); 494} 495 496CancelCallback DriveAPIService::GetAboutResource( 497 const GetAboutResourceCallback& callback) { 498 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 499 DCHECK(!callback.is_null()); 500 501 return sender_->StartRequestWithRetry( 502 new GetAboutRequest( 503 sender_.get(), 504 url_generator_, 505 callback)); 506} 507 508CancelCallback DriveAPIService::GetAppList(const GetAppListCallback& callback) { 509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 510 DCHECK(!callback.is_null()); 511 512 return sender_->StartRequestWithRetry(new GetApplistRequest( 513 sender_.get(), 514 url_generator_, 515 base::Bind(&ParseAppListAndRun, callback))); 516} 517 518CancelCallback DriveAPIService::DownloadFile( 519 const base::FilePath& local_cache_path, 520 const std::string& resource_id, 521 const DownloadActionCallback& download_action_callback, 522 const GetContentCallback& get_content_callback, 523 const ProgressCallback& progress_callback) { 524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 525 DCHECK(!download_action_callback.is_null()); 526 // get_content_callback may be null. 527 528 return sender_->StartRequestWithRetry( 529 new DownloadFileRequest(sender_.get(), 530 url_generator_, 531 resource_id, 532 local_cache_path, 533 download_action_callback, 534 get_content_callback, 535 progress_callback)); 536} 537 538CancelCallback DriveAPIService::DeleteResource( 539 const std::string& resource_id, 540 const std::string& etag, 541 const EntryActionCallback& callback) { 542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 543 DCHECK(!callback.is_null()); 544 545 return sender_->StartRequestWithRetry(new TrashResourceRequest( 546 sender_.get(), 547 url_generator_, 548 resource_id, 549 callback)); 550} 551 552CancelCallback DriveAPIService::AddNewDirectory( 553 const std::string& parent_resource_id, 554 const std::string& directory_title, 555 const GetResourceEntryCallback& callback) { 556 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 557 DCHECK(!callback.is_null()); 558 559 return sender_->StartRequestWithRetry( 560 new CreateDirectoryRequest( 561 sender_.get(), 562 url_generator_, 563 parent_resource_id, 564 directory_title, 565 base::Bind(&ParseResourceEntryAndRun, callback))); 566} 567 568CancelCallback DriveAPIService::CopyResource( 569 const std::string& resource_id, 570 const std::string& parent_resource_id, 571 const std::string& new_title, 572 const GetResourceEntryCallback& callback) { 573 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 574 DCHECK(!callback.is_null()); 575 576 return sender_->StartRequestWithRetry( 577 new CopyResourceRequest( 578 sender_.get(), 579 url_generator_, 580 resource_id, 581 parent_resource_id, 582 new_title, 583 base::Bind(&ParseResourceEntryAndRun, callback))); 584} 585 586CancelCallback DriveAPIService::CopyHostedDocument( 587 const std::string& resource_id, 588 const std::string& new_title, 589 const GetResourceEntryCallback& callback) { 590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 591 DCHECK(!callback.is_null()); 592 593 return sender_->StartRequestWithRetry( 594 new CopyResourceRequest( 595 sender_.get(), 596 url_generator_, 597 resource_id, 598 std::string(), // parent_resource_id. 599 new_title, 600 base::Bind(&ParseResourceEntryAndRun, callback))); 601} 602 603CancelCallback DriveAPIService::RenameResource( 604 const std::string& resource_id, 605 const std::string& new_title, 606 const EntryActionCallback& callback) { 607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 608 DCHECK(!callback.is_null()); 609 610 return sender_->StartRequestWithRetry( 611 new RenameResourceRequest( 612 sender_.get(), 613 url_generator_, 614 resource_id, 615 new_title, 616 callback)); 617} 618 619CancelCallback DriveAPIService::TouchResource( 620 const std::string& resource_id, 621 const base::Time& modified_date, 622 const base::Time& last_viewed_by_me_date, 623 const GetResourceEntryCallback& callback) { 624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 625 DCHECK(!modified_date.is_null()); 626 DCHECK(!last_viewed_by_me_date.is_null()); 627 DCHECK(!callback.is_null()); 628 629 return sender_->StartRequestWithRetry( 630 new TouchResourceRequest( 631 sender_.get(), 632 url_generator_, 633 resource_id, 634 modified_date, 635 last_viewed_by_me_date, 636 base::Bind(&ParseResourceEntryAndRun, callback))); 637} 638 639CancelCallback DriveAPIService::AddResourceToDirectory( 640 const std::string& parent_resource_id, 641 const std::string& resource_id, 642 const EntryActionCallback& callback) { 643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 644 DCHECK(!callback.is_null()); 645 646 return sender_->StartRequestWithRetry( 647 new InsertResourceRequest( 648 sender_.get(), 649 url_generator_, 650 parent_resource_id, 651 resource_id, 652 callback)); 653} 654 655CancelCallback DriveAPIService::RemoveResourceFromDirectory( 656 const std::string& parent_resource_id, 657 const std::string& resource_id, 658 const EntryActionCallback& callback) { 659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 660 DCHECK(!callback.is_null()); 661 662 return sender_->StartRequestWithRetry( 663 new DeleteResourceRequest( 664 sender_.get(), 665 url_generator_, 666 parent_resource_id, 667 resource_id, 668 callback)); 669} 670 671CancelCallback DriveAPIService::InitiateUploadNewFile( 672 const std::string& content_type, 673 int64 content_length, 674 const std::string& parent_resource_id, 675 const std::string& title, 676 const InitiateUploadCallback& callback) { 677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 678 DCHECK(!callback.is_null()); 679 680 return sender_->StartRequestWithRetry( 681 new InitiateUploadNewFileRequest( 682 sender_.get(), 683 url_generator_, 684 content_type, 685 content_length, 686 parent_resource_id, 687 title, 688 callback)); 689} 690 691CancelCallback DriveAPIService::InitiateUploadExistingFile( 692 const std::string& content_type, 693 int64 content_length, 694 const std::string& resource_id, 695 const std::string& etag, 696 const InitiateUploadCallback& callback) { 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 698 DCHECK(!callback.is_null()); 699 700 return sender_->StartRequestWithRetry( 701 new InitiateUploadExistingFileRequest( 702 sender_.get(), 703 url_generator_, 704 content_type, 705 content_length, 706 resource_id, 707 etag, 708 callback)); 709} 710 711CancelCallback DriveAPIService::ResumeUpload( 712 const GURL& upload_url, 713 int64 start_position, 714 int64 end_position, 715 int64 content_length, 716 const std::string& content_type, 717 const base::FilePath& local_file_path, 718 const UploadRangeCallback& callback, 719 const ProgressCallback& progress_callback) { 720 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 721 DCHECK(!callback.is_null()); 722 723 return sender_->StartRequestWithRetry( 724 new ResumeUploadRequest( 725 sender_.get(), 726 upload_url, 727 start_position, 728 end_position, 729 content_length, 730 content_type, 731 local_file_path, 732 base::Bind(&ParseResourceEntryForUploadRangeAndRun, callback), 733 progress_callback)); 734} 735 736CancelCallback DriveAPIService::GetUploadStatus( 737 const GURL& upload_url, 738 int64 content_length, 739 const UploadRangeCallback& callback) { 740 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 741 DCHECK(!callback.is_null()); 742 743 return sender_->StartRequestWithRetry(new GetUploadStatusRequest( 744 sender_.get(), 745 upload_url, 746 content_length, 747 base::Bind(&ParseResourceEntryForUploadRangeAndRun, callback))); 748} 749 750CancelCallback DriveAPIService::AuthorizeApp( 751 const std::string& resource_id, 752 const std::string& app_id, 753 const AuthorizeAppCallback& callback) { 754 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 755 DCHECK(!callback.is_null()); 756 757 return sender_->StartRequestWithRetry(new GetFileRequest( 758 sender_.get(), 759 url_generator_, 760 resource_id, 761 base::Bind(&ExtractOpenUrlAndRun, app_id, callback))); 762} 763 764bool DriveAPIService::HasAccessToken() const { 765 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 766 return sender_->auth_service()->HasAccessToken(); 767} 768 769void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) { 770 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 771 DCHECK(!callback.is_null()); 772 773 const std::string access_token = sender_->auth_service()->access_token(); 774 if (!access_token.empty()) { 775 callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token); 776 return; 777 } 778 779 // Retrieve the new auth token. 780 sender_->auth_service()->StartAuthentication(callback); 781} 782 783bool DriveAPIService::HasRefreshToken() const { 784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 785 return sender_->auth_service()->HasRefreshToken(); 786} 787 788void DriveAPIService::ClearAccessToken() { 789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 790 sender_->auth_service()->ClearAccessToken(); 791} 792 793void DriveAPIService::ClearRefreshToken() { 794 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 795 sender_->auth_service()->ClearRefreshToken(); 796} 797 798void DriveAPIService::OnOAuth2RefreshTokenChanged() { 799 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 800 if (CanSendRequest()) { 801 FOR_EACH_OBSERVER( 802 DriveServiceObserver, observers_, OnReadyToSendRequests()); 803 } else if (!HasRefreshToken()) { 804 FOR_EACH_OBSERVER( 805 DriveServiceObserver, observers_, OnRefreshTokenInvalid()); 806 } 807} 808 809} // namespace drive 810