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/google_apis/drive_api_requests.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/json/json_writer.h" 10#include "base/values.h" 11#include "chrome/browser/google_apis/drive_api_parser.h" 12#include "chrome/browser/google_apis/request_util.h" 13#include "chrome/browser/google_apis/time_util.h" 14 15namespace google_apis { 16namespace { 17 18const char kContentTypeApplicationJson[] = "application/json"; 19const char kDirectoryMimeType[] = "application/vnd.google-apps.folder"; 20const char kParentLinkKind[] = "drive#fileLink"; 21 22// Parses the JSON value to a resource typed |T| and runs |callback| on the UI 23// thread once parsing is done. 24template<typename T> 25void ParseJsonAndRun( 26 const base::Callback<void(GDataErrorCode, scoped_ptr<T>)>& callback, 27 GDataErrorCode error, 28 scoped_ptr<base::Value> value) { 29 DCHECK(!callback.is_null()); 30 31 scoped_ptr<T> resource; 32 if (value) { 33 resource = T::CreateFrom(*value); 34 if (!resource) { 35 // Failed to parse the JSON value, although the JSON value is available, 36 // so let the callback know the parsing error. 37 error = GDATA_PARSE_ERROR; 38 } 39 } 40 41 callback.Run(error, resource.Pass()); 42} 43 44// Parses the JSON value to FileResource instance and runs |callback| on the 45// UI thread once parsing is done. 46// This is customized version of ParseJsonAndRun defined above to adapt the 47// remaining response type. 48void ParseFileResourceWithUploadRangeAndRun( 49 const drive::UploadRangeCallback& callback, 50 const UploadRangeResponse& response, 51 scoped_ptr<base::Value> value) { 52 DCHECK(!callback.is_null()); 53 54 scoped_ptr<FileResource> file_resource; 55 if (value) { 56 file_resource = FileResource::CreateFrom(*value); 57 if (!file_resource) { 58 callback.Run( 59 UploadRangeResponse(GDATA_PARSE_ERROR, 60 response.start_position_received, 61 response.end_position_received), 62 scoped_ptr<FileResource>()); 63 return; 64 } 65 } 66 67 callback.Run(response, file_resource.Pass()); 68} 69 70} // namespace 71 72//============================== GetAboutRequest ============================= 73 74GetAboutRequest::GetAboutRequest( 75 RequestSender* sender, 76 const DriveApiUrlGenerator& url_generator, 77 const GetAboutResourceCallback& callback) 78 : GetDataRequest(sender, 79 base::Bind(&ParseJsonAndRun<AboutResource>, callback)), 80 url_generator_(url_generator) { 81 DCHECK(!callback.is_null()); 82} 83 84GetAboutRequest::~GetAboutRequest() {} 85 86GURL GetAboutRequest::GetURL() const { 87 return url_generator_.GetAboutUrl(); 88} 89 90//============================== GetApplistRequest =========================== 91 92GetApplistRequest::GetApplistRequest( 93 RequestSender* sender, 94 const DriveApiUrlGenerator& url_generator, 95 const GetDataCallback& callback) 96 : GetDataRequest(sender, callback), 97 url_generator_(url_generator) { 98 DCHECK(!callback.is_null()); 99} 100 101GetApplistRequest::~GetApplistRequest() {} 102 103GURL GetApplistRequest::GetURL() const { 104 return url_generator_.GetApplistUrl(); 105} 106 107//============================ GetChangelistRequest ========================== 108 109GetChangelistRequest::GetChangelistRequest( 110 RequestSender* sender, 111 const DriveApiUrlGenerator& url_generator, 112 bool include_deleted, 113 int64 start_changestamp, 114 int max_results, 115 const GetDataCallback& callback) 116 : GetDataRequest(sender, callback), 117 url_generator_(url_generator), 118 include_deleted_(include_deleted), 119 start_changestamp_(start_changestamp), 120 max_results_(max_results) { 121 DCHECK(!callback.is_null()); 122} 123 124GetChangelistRequest::~GetChangelistRequest() {} 125 126GURL GetChangelistRequest::GetURL() const { 127 return url_generator_.GetChangelistUrl( 128 include_deleted_, start_changestamp_, max_results_); 129} 130 131//============================= GetFilelistRequest =========================== 132 133GetFilelistRequest::GetFilelistRequest( 134 RequestSender* sender, 135 const DriveApiUrlGenerator& url_generator, 136 const std::string& search_string, 137 int max_results, 138 const GetDataCallback& callback) 139 : GetDataRequest(sender, callback), 140 url_generator_(url_generator), 141 search_string_(search_string), 142 max_results_(max_results) { 143 DCHECK(!callback.is_null()); 144} 145 146GetFilelistRequest::~GetFilelistRequest() {} 147 148GURL GetFilelistRequest::GetURL() const { 149 return url_generator_.GetFilelistUrl(search_string_, max_results_); 150} 151 152//=============================== GetFileRequest ============================= 153 154GetFileRequest::GetFileRequest( 155 RequestSender* sender, 156 const DriveApiUrlGenerator& url_generator, 157 const std::string& file_id, 158 const FileResourceCallback& callback) 159 : GetDataRequest(sender, 160 base::Bind(&ParseJsonAndRun<FileResource>, callback)), 161 url_generator_(url_generator), 162 file_id_(file_id) { 163 DCHECK(!callback.is_null()); 164} 165 166GetFileRequest::~GetFileRequest() {} 167 168GURL GetFileRequest::GetURL() const { 169 return url_generator_.GetFileUrl(file_id_); 170} 171 172namespace drive { 173 174//======================= ContinueGetFileListRequest ========================= 175 176ContinueGetFileListRequest::ContinueGetFileListRequest( 177 RequestSender* sender, 178 const GURL& url, 179 const GetDataCallback& callback) 180 : GetDataRequest(sender, callback), 181 url_(url) { 182 DCHECK(!callback.is_null()); 183} 184 185ContinueGetFileListRequest::~ContinueGetFileListRequest() {} 186 187GURL ContinueGetFileListRequest::GetURL() const { 188 return url_; 189} 190 191//========================== CreateDirectoryRequest ========================== 192 193CreateDirectoryRequest::CreateDirectoryRequest( 194 RequestSender* sender, 195 const DriveApiUrlGenerator& url_generator, 196 const std::string& parent_resource_id, 197 const std::string& directory_title, 198 const FileResourceCallback& callback) 199 : GetDataRequest(sender, 200 base::Bind(&ParseJsonAndRun<FileResource>, callback)), 201 url_generator_(url_generator), 202 parent_resource_id_(parent_resource_id), 203 directory_title_(directory_title) { 204 DCHECK(!callback.is_null()); 205 DCHECK(!parent_resource_id_.empty()); 206 DCHECK(!directory_title_.empty()); 207} 208 209CreateDirectoryRequest::~CreateDirectoryRequest() {} 210 211GURL CreateDirectoryRequest::GetURL() const { 212 return url_generator_.GetFilesUrl(); 213} 214 215net::URLFetcher::RequestType CreateDirectoryRequest::GetRequestType() const { 216 return net::URLFetcher::POST; 217} 218 219bool CreateDirectoryRequest::GetContentData(std::string* upload_content_type, 220 std::string* upload_content) { 221 *upload_content_type = kContentTypeApplicationJson; 222 223 base::DictionaryValue root; 224 root.SetString("title", directory_title_); 225 { 226 base::DictionaryValue* parent_value = new base::DictionaryValue; 227 parent_value->SetString("id", parent_resource_id_); 228 base::ListValue* parent_list_value = new base::ListValue; 229 parent_list_value->Append(parent_value); 230 root.Set("parents", parent_list_value); 231 } 232 root.SetString("mimeType", kDirectoryMimeType); 233 234 base::JSONWriter::Write(&root, upload_content); 235 236 DVLOG(1) << "CreateDirectory data: " << *upload_content_type << ", [" 237 << *upload_content << "]"; 238 return true; 239} 240 241//=========================== RenameResourceRequest ========================== 242 243RenameResourceRequest::RenameResourceRequest( 244 RequestSender* sender, 245 const DriveApiUrlGenerator& url_generator, 246 const std::string& resource_id, 247 const std::string& new_title, 248 const EntryActionCallback& callback) 249 : EntryActionRequest(sender, callback), 250 url_generator_(url_generator), 251 resource_id_(resource_id), 252 new_title_(new_title) { 253 DCHECK(!callback.is_null()); 254} 255 256RenameResourceRequest::~RenameResourceRequest() {} 257 258net::URLFetcher::RequestType RenameResourceRequest::GetRequestType() const { 259 return net::URLFetcher::PATCH; 260} 261 262std::vector<std::string> 263RenameResourceRequest::GetExtraRequestHeaders() const { 264 std::vector<std::string> headers; 265 headers.push_back(util::kIfMatchAllHeader); 266 return headers; 267} 268 269GURL RenameResourceRequest::GetURL() const { 270 return url_generator_.GetFileUrl(resource_id_); 271} 272 273bool RenameResourceRequest::GetContentData(std::string* upload_content_type, 274 std::string* upload_content) { 275 *upload_content_type = kContentTypeApplicationJson; 276 277 base::DictionaryValue root; 278 root.SetString("title", new_title_); 279 base::JSONWriter::Write(&root, upload_content); 280 281 DVLOG(1) << "RenameResource data: " << *upload_content_type << ", [" 282 << *upload_content << "]"; 283 return true; 284} 285 286//=========================== TouchResourceRequest =========================== 287 288TouchResourceRequest::TouchResourceRequest( 289 RequestSender* sender, 290 const DriveApiUrlGenerator& url_generator, 291 const std::string& resource_id, 292 const base::Time& modified_date, 293 const base::Time& last_viewed_by_me_date, 294 const FileResourceCallback& callback) 295 : GetDataRequest(sender, 296 base::Bind(&ParseJsonAndRun<FileResource>, callback)), 297 url_generator_(url_generator), 298 resource_id_(resource_id), 299 modified_date_(modified_date), 300 last_viewed_by_me_date_(last_viewed_by_me_date) { 301 DCHECK(!modified_date.is_null()); 302 DCHECK(!last_viewed_by_me_date.is_null()); 303 DCHECK(!callback.is_null()); 304} 305 306TouchResourceRequest::~TouchResourceRequest() {} 307 308net::URLFetcher::RequestType TouchResourceRequest::GetRequestType() const { 309 return net::URLFetcher::PATCH; 310} 311 312std::vector<std::string> 313TouchResourceRequest::GetExtraRequestHeaders() const { 314 std::vector<std::string> headers; 315 headers.push_back(util::kIfMatchAllHeader); 316 return headers; 317} 318 319GURL TouchResourceRequest::GetURL() const { 320 return url_generator_.GetFileTouchUrl(resource_id_); 321} 322 323bool TouchResourceRequest::GetContentData(std::string* upload_content_type, 324 std::string* upload_content) { 325 *upload_content_type = kContentTypeApplicationJson; 326 327 base::DictionaryValue root; 328 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_)); 329 root.SetString("lastViewedByMeDate", 330 util::FormatTimeAsString(last_viewed_by_me_date_)); 331 base::JSONWriter::Write(&root, upload_content); 332 333 DVLOG(1) << "TouchResource data: " << *upload_content_type << ", [" 334 << *upload_content << "]"; 335 return true; 336} 337 338//=========================== CopyResourceRequest ============================ 339 340CopyResourceRequest::CopyResourceRequest( 341 RequestSender* sender, 342 const DriveApiUrlGenerator& url_generator, 343 const std::string& resource_id, 344 const std::string& parent_resource_id, 345 const std::string& new_title, 346 const FileResourceCallback& callback) 347 : GetDataRequest(sender, 348 base::Bind(&ParseJsonAndRun<FileResource>, callback)), 349 url_generator_(url_generator), 350 resource_id_(resource_id), 351 parent_resource_id_(parent_resource_id), 352 new_title_(new_title) { 353 DCHECK(!callback.is_null()); 354} 355 356CopyResourceRequest::~CopyResourceRequest() { 357} 358 359net::URLFetcher::RequestType CopyResourceRequest::GetRequestType() const { 360 return net::URLFetcher::POST; 361} 362 363GURL CopyResourceRequest::GetURL() const { 364 return url_generator_.GetFileCopyUrl(resource_id_); 365} 366 367bool CopyResourceRequest::GetContentData(std::string* upload_content_type, 368 std::string* upload_content) { 369 *upload_content_type = kContentTypeApplicationJson; 370 371 base::DictionaryValue root; 372 root.SetString("title", new_title_); 373 374 if (!parent_resource_id_.empty()) { 375 // Set the parent resource (destination directory) of the new resource. 376 base::ListValue* parents = new base::ListValue; 377 root.Set("parents", parents); 378 base::DictionaryValue* parent_value = new base::DictionaryValue; 379 parents->Append(parent_value); 380 parent_value->SetString("id", parent_resource_id_); 381 } 382 383 base::JSONWriter::Write(&root, upload_content); 384 385 DVLOG(1) << "CopyResource data: " << *upload_content_type << ", [" 386 << *upload_content << "]"; 387 return true; 388} 389 390//=========================== TrashResourceRequest =========================== 391 392TrashResourceRequest::TrashResourceRequest( 393 RequestSender* sender, 394 const DriveApiUrlGenerator& url_generator, 395 const std::string& resource_id, 396 const EntryActionCallback& callback) 397 : EntryActionRequest(sender, callback), 398 url_generator_(url_generator), 399 resource_id_(resource_id) { 400 DCHECK(!callback.is_null()); 401} 402 403TrashResourceRequest::~TrashResourceRequest() {} 404 405GURL TrashResourceRequest::GetURL() const { 406 return url_generator_.GetFileTrashUrl(resource_id_); 407} 408 409net::URLFetcher::RequestType TrashResourceRequest::GetRequestType() const { 410 return net::URLFetcher::POST; 411} 412 413//========================== InsertResourceRequest =========================== 414 415InsertResourceRequest::InsertResourceRequest( 416 RequestSender* sender, 417 const DriveApiUrlGenerator& url_generator, 418 const std::string& parent_resource_id, 419 const std::string& resource_id, 420 const EntryActionCallback& callback) 421 : EntryActionRequest(sender, callback), 422 url_generator_(url_generator), 423 parent_resource_id_(parent_resource_id), 424 resource_id_(resource_id) { 425 DCHECK(!callback.is_null()); 426} 427 428InsertResourceRequest::~InsertResourceRequest() {} 429 430GURL InsertResourceRequest::GetURL() const { 431 return url_generator_.GetChildrenUrl(parent_resource_id_); 432} 433 434net::URLFetcher::RequestType InsertResourceRequest::GetRequestType() const { 435 return net::URLFetcher::POST; 436} 437 438bool InsertResourceRequest::GetContentData(std::string* upload_content_type, 439 std::string* upload_content) { 440 *upload_content_type = kContentTypeApplicationJson; 441 442 base::DictionaryValue root; 443 root.SetString("id", resource_id_); 444 base::JSONWriter::Write(&root, upload_content); 445 446 DVLOG(1) << "InsertResource data: " << *upload_content_type << ", [" 447 << *upload_content << "]"; 448 return true; 449} 450 451//========================== DeleteResourceRequest =========================== 452 453DeleteResourceRequest::DeleteResourceRequest( 454 RequestSender* sender, 455 const DriveApiUrlGenerator& url_generator, 456 const std::string& parent_resource_id, 457 const std::string& resource_id, 458 const EntryActionCallback& callback) 459 : EntryActionRequest(sender, callback), 460 url_generator_(url_generator), 461 parent_resource_id_(parent_resource_id), 462 resource_id_(resource_id) { 463 DCHECK(!callback.is_null()); 464} 465 466DeleteResourceRequest::~DeleteResourceRequest() {} 467 468GURL DeleteResourceRequest::GetURL() const { 469 return url_generator_.GetChildrenUrlForRemoval( 470 parent_resource_id_, resource_id_); 471} 472 473net::URLFetcher::RequestType DeleteResourceRequest::GetRequestType() const { 474 return net::URLFetcher::DELETE_REQUEST; 475} 476 477//======================= InitiateUploadNewFileRequest ======================= 478 479InitiateUploadNewFileRequest::InitiateUploadNewFileRequest( 480 RequestSender* sender, 481 const DriveApiUrlGenerator& url_generator, 482 const std::string& content_type, 483 int64 content_length, 484 const std::string& parent_resource_id, 485 const std::string& title, 486 const InitiateUploadCallback& callback) 487 : InitiateUploadRequestBase(sender, 488 callback, 489 content_type, 490 content_length), 491 url_generator_(url_generator), 492 parent_resource_id_(parent_resource_id), 493 title_(title) { 494} 495 496InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {} 497 498GURL InitiateUploadNewFileRequest::GetURL() const { 499 return url_generator_.GetInitiateUploadNewFileUrl(); 500} 501 502net::URLFetcher::RequestType 503InitiateUploadNewFileRequest::GetRequestType() const { 504 return net::URLFetcher::POST; 505} 506 507bool InitiateUploadNewFileRequest::GetContentData( 508 std::string* upload_content_type, 509 std::string* upload_content) { 510 *upload_content_type = kContentTypeApplicationJson; 511 512 base::DictionaryValue root; 513 root.SetString("title", title_); 514 515 // Fill parent link. 516 { 517 scoped_ptr<base::DictionaryValue> parent(new base::DictionaryValue); 518 parent->SetString("kind", kParentLinkKind); 519 parent->SetString("id", parent_resource_id_); 520 521 scoped_ptr<base::ListValue> parents(new base::ListValue); 522 parents->Append(parent.release()); 523 524 root.Set("parents", parents.release()); 525 } 526 527 base::JSONWriter::Write(&root, upload_content); 528 529 DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", [" 530 << *upload_content << "]"; 531 return true; 532} 533 534//===================== InitiateUploadExistingFileRequest ==================== 535 536InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest( 537 RequestSender* sender, 538 const DriveApiUrlGenerator& url_generator, 539 const std::string& content_type, 540 int64 content_length, 541 const std::string& resource_id, 542 const std::string& etag, 543 const InitiateUploadCallback& callback) 544 : InitiateUploadRequestBase(sender, 545 callback, 546 content_type, 547 content_length), 548 url_generator_(url_generator), 549 resource_id_(resource_id), 550 etag_(etag) { 551} 552 553InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {} 554 555GURL InitiateUploadExistingFileRequest::GetURL() const { 556 return url_generator_.GetInitiateUploadExistingFileUrl(resource_id_); 557} 558 559net::URLFetcher::RequestType 560InitiateUploadExistingFileRequest::GetRequestType() const { 561 return net::URLFetcher::PUT; 562} 563 564std::vector<std::string> 565InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const { 566 std::vector<std::string> headers( 567 InitiateUploadRequestBase::GetExtraRequestHeaders()); 568 headers.push_back(util::GenerateIfMatchHeader(etag_)); 569 return headers; 570} 571 572//============================ ResumeUploadRequest =========================== 573 574ResumeUploadRequest::ResumeUploadRequest( 575 RequestSender* sender, 576 const GURL& upload_location, 577 int64 start_position, 578 int64 end_position, 579 int64 content_length, 580 const std::string& content_type, 581 const base::FilePath& local_file_path, 582 const UploadRangeCallback& callback, 583 const ProgressCallback& progress_callback) 584 : ResumeUploadRequestBase(sender, 585 upload_location, 586 start_position, 587 end_position, 588 content_length, 589 content_type, 590 local_file_path), 591 callback_(callback), 592 progress_callback_(progress_callback) { 593 DCHECK(!callback_.is_null()); 594} 595 596ResumeUploadRequest::~ResumeUploadRequest() {} 597 598void ResumeUploadRequest::OnRangeRequestComplete( 599 const UploadRangeResponse& response, 600 scoped_ptr<base::Value> value) { 601 DCHECK(CalledOnValidThread()); 602 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass()); 603} 604 605void ResumeUploadRequest::OnURLFetchUploadProgress( 606 const net::URLFetcher* source, int64 current, int64 total) { 607 if (!progress_callback_.is_null()) 608 progress_callback_.Run(current, total); 609} 610 611//========================== GetUploadStatusRequest ========================== 612 613GetUploadStatusRequest::GetUploadStatusRequest( 614 RequestSender* sender, 615 const GURL& upload_url, 616 int64 content_length, 617 const UploadRangeCallback& callback) 618 : GetUploadStatusRequestBase(sender, 619 upload_url, 620 content_length), 621 callback_(callback) { 622 DCHECK(!callback.is_null()); 623} 624 625GetUploadStatusRequest::~GetUploadStatusRequest() {} 626 627void GetUploadStatusRequest::OnRangeRequestComplete( 628 const UploadRangeResponse& response, 629 scoped_ptr<base::Value> value) { 630 DCHECK(CalledOnValidThread()); 631 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass()); 632} 633 634//========================== DownloadFileRequest ========================== 635 636DownloadFileRequest::DownloadFileRequest( 637 RequestSender* sender, 638 const DriveApiUrlGenerator& url_generator, 639 const std::string& resource_id, 640 const base::FilePath& output_file_path, 641 const DownloadActionCallback& download_action_callback, 642 const GetContentCallback& get_content_callback, 643 const ProgressCallback& progress_callback) 644 : DownloadFileRequestBase( 645 sender, 646 download_action_callback, 647 get_content_callback, 648 progress_callback, 649 url_generator.GenerateDownloadFileUrl(resource_id), 650 output_file_path) { 651} 652 653DownloadFileRequest::~DownloadFileRequest() { 654} 655 656} // namespace drive 657} // namespace google_apis 658