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