| 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 |