// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/google_apis/drive_api_requests.h" #include "base/bind.h" #include "base/callback.h" #include "base/json/json_writer.h" #include "base/values.h" #include "chrome/browser/google_apis/drive_api_parser.h" #include "chrome/browser/google_apis/request_util.h" #include "chrome/browser/google_apis/time_util.h" #include "content/public/browser/browser_thread.h" using content::BrowserThread; namespace google_apis { namespace { const char kContentTypeApplicationJson[] = "application/json"; const char kDirectoryMimeType[] = "application/vnd.google-apps.folder"; const char kParentLinkKind[] = "drive#fileLink"; // Parses the JSON value to a resource typed |T| and runs |callback| on the UI // thread once parsing is done. template void ParseJsonAndRun( const base::Callback)>& callback, GDataErrorCode error, scoped_ptr value) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!callback.is_null()); scoped_ptr resource; if (value) { resource = T::CreateFrom(*value); if (!resource) { // Failed to parse the JSON value, although the JSON value is available, // so let the callback know the parsing error. error = GDATA_PARSE_ERROR; } } callback.Run(error, resource.Pass()); } // Parses the JSON value to FileResource instance and runs |callback| on the // UI thread once parsing is done. // This is customized version of ParseJsonAndRun defined above to adapt the // remaining response type. void ParseFileResourceWithUploadRangeAndRun( const drive::UploadRangeCallback& callback, const UploadRangeResponse& response, scoped_ptr value) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!callback.is_null()); scoped_ptr file_resource; if (value) { file_resource = FileResource::CreateFrom(*value); if (!file_resource) { callback.Run( UploadRangeResponse(GDATA_PARSE_ERROR, response.start_position_received, response.end_position_received), scoped_ptr()); return; } } callback.Run(response, file_resource.Pass()); } } // namespace //============================== GetAboutRequest ============================= GetAboutRequest::GetAboutRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const GetAboutResourceCallback& callback) : GetDataRequest(runner, url_request_context_getter, base::Bind(&ParseJsonAndRun, callback)), url_generator_(url_generator) { DCHECK(!callback.is_null()); } GetAboutRequest::~GetAboutRequest() {} GURL GetAboutRequest::GetURL() const { return url_generator_.GetAboutUrl(); } //============================== GetApplistRequest =========================== GetApplistRequest::GetApplistRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const GetDataCallback& callback) : GetDataRequest(runner, url_request_context_getter, callback), url_generator_(url_generator) { DCHECK(!callback.is_null()); } GetApplistRequest::~GetApplistRequest() {} GURL GetApplistRequest::GetURL() const { return url_generator_.GetApplistUrl(); } //============================ GetChangelistRequest ========================== GetChangelistRequest::GetChangelistRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, bool include_deleted, int64 start_changestamp, int max_results, const GetDataCallback& callback) : GetDataRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), include_deleted_(include_deleted), start_changestamp_(start_changestamp), max_results_(max_results) { DCHECK(!callback.is_null()); } GetChangelistRequest::~GetChangelistRequest() {} GURL GetChangelistRequest::GetURL() const { return url_generator_.GetChangelistUrl( include_deleted_, start_changestamp_, max_results_); } //============================= GetFilelistRequest =========================== GetFilelistRequest::GetFilelistRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& search_string, int max_results, const GetDataCallback& callback) : GetDataRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), search_string_(search_string), max_results_(max_results) { DCHECK(!callback.is_null()); } GetFilelistRequest::~GetFilelistRequest() {} GURL GetFilelistRequest::GetURL() const { return url_generator_.GetFilelistUrl(search_string_, max_results_); } //=============================== GetFileRequest ============================= GetFileRequest::GetFileRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& file_id, const FileResourceCallback& callback) : GetDataRequest(runner, url_request_context_getter, base::Bind(&ParseJsonAndRun, callback)), url_generator_(url_generator), file_id_(file_id) { DCHECK(!callback.is_null()); } GetFileRequest::~GetFileRequest() {} GURL GetFileRequest::GetURL() const { return url_generator_.GetFileUrl(file_id_); } namespace drive { //======================= ContinueGetFileListRequest ========================= ContinueGetFileListRequest::ContinueGetFileListRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const GURL& url, const GetDataCallback& callback) : GetDataRequest(runner, url_request_context_getter, callback), url_(url) { DCHECK(!callback.is_null()); } ContinueGetFileListRequest::~ContinueGetFileListRequest() {} GURL ContinueGetFileListRequest::GetURL() const { return url_; } //========================== CreateDirectoryRequest ========================== CreateDirectoryRequest::CreateDirectoryRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& parent_resource_id, const std::string& directory_name, const FileResourceCallback& callback) : GetDataRequest(runner, url_request_context_getter, base::Bind(&ParseJsonAndRun, callback)), url_generator_(url_generator), parent_resource_id_(parent_resource_id), directory_name_(directory_name) { DCHECK(!callback.is_null()); DCHECK(!parent_resource_id_.empty()); DCHECK(!directory_name_.empty()); } CreateDirectoryRequest::~CreateDirectoryRequest() {} GURL CreateDirectoryRequest::GetURL() const { return url_generator_.GetFilesUrl(); } net::URLFetcher::RequestType CreateDirectoryRequest::GetRequestType() const { return net::URLFetcher::POST; } bool CreateDirectoryRequest::GetContentData(std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("title", directory_name_); { base::DictionaryValue* parent_value = new base::DictionaryValue; parent_value->SetString("id", parent_resource_id_); base::ListValue* parent_list_value = new base::ListValue; parent_list_value->Append(parent_value); root.Set("parents", parent_list_value); } root.SetString("mimeType", kDirectoryMimeType); base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "CreateDirectory data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //=========================== RenameResourceRequest ========================== RenameResourceRequest::RenameResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& resource_id, const std::string& new_name, const EntryActionCallback& callback) : EntryActionRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), resource_id_(resource_id), new_name_(new_name) { DCHECK(!callback.is_null()); } RenameResourceRequest::~RenameResourceRequest() {} net::URLFetcher::RequestType RenameResourceRequest::GetRequestType() const { return net::URLFetcher::PATCH; } std::vector RenameResourceRequest::GetExtraRequestHeaders() const { std::vector headers; headers.push_back(util::kIfMatchAllHeader); return headers; } GURL RenameResourceRequest::GetURL() const { return url_generator_.GetFileUrl(resource_id_); } bool RenameResourceRequest::GetContentData(std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("title", new_name_); base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "RenameResource data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //=========================== TouchResourceRequest =========================== TouchResourceRequest::TouchResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& resource_id, const base::Time& modified_date, const base::Time& last_viewed_by_me_date, const FileResourceCallback& callback) : GetDataRequest(runner, url_request_context_getter, base::Bind(&ParseJsonAndRun, callback)), url_generator_(url_generator), resource_id_(resource_id), modified_date_(modified_date), last_viewed_by_me_date_(last_viewed_by_me_date) { DCHECK(!modified_date.is_null()); DCHECK(!last_viewed_by_me_date.is_null()); DCHECK(!callback.is_null()); } TouchResourceRequest::~TouchResourceRequest() {} net::URLFetcher::RequestType TouchResourceRequest::GetRequestType() const { return net::URLFetcher::PATCH; } std::vector TouchResourceRequest::GetExtraRequestHeaders() const { std::vector headers; headers.push_back(util::kIfMatchAllHeader); return headers; } GURL TouchResourceRequest::GetURL() const { return url_generator_.GetFileTouchUrl(resource_id_); } bool TouchResourceRequest::GetContentData(std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_)); root.SetString("lastViewedByMeDate", util::FormatTimeAsString(last_viewed_by_me_date_)); base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "TouchResource data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //=========================== CopyResourceRequest ============================ CopyResourceRequest::CopyResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& resource_id, const std::string& parent_resource_id, const std::string& new_name, const FileResourceCallback& callback) : GetDataRequest(runner, url_request_context_getter, base::Bind(&ParseJsonAndRun, callback)), url_generator_(url_generator), resource_id_(resource_id), parent_resource_id_(parent_resource_id), new_name_(new_name) { DCHECK(!callback.is_null()); } CopyResourceRequest::~CopyResourceRequest() { } net::URLFetcher::RequestType CopyResourceRequest::GetRequestType() const { return net::URLFetcher::POST; } GURL CopyResourceRequest::GetURL() const { return url_generator_.GetFileCopyUrl(resource_id_); } bool CopyResourceRequest::GetContentData(std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("title", new_name_); if (!parent_resource_id_.empty()) { // Set the parent resource (destination directory) of the new resource. base::ListValue* parents = new base::ListValue; root.Set("parents", parents); base::DictionaryValue* parent_value = new base::DictionaryValue; parents->Append(parent_value); parent_value->SetString("id", parent_resource_id_); } base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "CopyResource data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //=========================== TrashResourceRequest =========================== TrashResourceRequest::TrashResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& resource_id, const EntryActionCallback& callback) : EntryActionRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), resource_id_(resource_id) { DCHECK(!callback.is_null()); } TrashResourceRequest::~TrashResourceRequest() {} GURL TrashResourceRequest::GetURL() const { return url_generator_.GetFileTrashUrl(resource_id_); } net::URLFetcher::RequestType TrashResourceRequest::GetRequestType() const { return net::URLFetcher::POST; } //========================== InsertResourceRequest =========================== InsertResourceRequest::InsertResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& parent_resource_id, const std::string& resource_id, const EntryActionCallback& callback) : EntryActionRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), parent_resource_id_(parent_resource_id), resource_id_(resource_id) { DCHECK(!callback.is_null()); } InsertResourceRequest::~InsertResourceRequest() {} GURL InsertResourceRequest::GetURL() const { return url_generator_.GetChildrenUrl(parent_resource_id_); } net::URLFetcher::RequestType InsertResourceRequest::GetRequestType() const { return net::URLFetcher::POST; } bool InsertResourceRequest::GetContentData(std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("id", resource_id_); base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "InsertResource data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //========================== DeleteResourceRequest =========================== DeleteResourceRequest::DeleteResourceRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& parent_resource_id, const std::string& resource_id, const EntryActionCallback& callback) : EntryActionRequest(runner, url_request_context_getter, callback), url_generator_(url_generator), parent_resource_id_(parent_resource_id), resource_id_(resource_id) { DCHECK(!callback.is_null()); } DeleteResourceRequest::~DeleteResourceRequest() {} GURL DeleteResourceRequest::GetURL() const { return url_generator_.GetChildrenUrlForRemoval( parent_resource_id_, resource_id_); } net::URLFetcher::RequestType DeleteResourceRequest::GetRequestType() const { return net::URLFetcher::DELETE_REQUEST; } //======================= InitiateUploadNewFileRequest ======================= InitiateUploadNewFileRequest::InitiateUploadNewFileRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& content_type, int64 content_length, const std::string& parent_resource_id, const std::string& title, const InitiateUploadCallback& callback) : InitiateUploadRequestBase(runner, url_request_context_getter, callback, content_type, content_length), url_generator_(url_generator), parent_resource_id_(parent_resource_id), title_(title) { } InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {} GURL InitiateUploadNewFileRequest::GetURL() const { return url_generator_.GetInitiateUploadNewFileUrl(); } net::URLFetcher::RequestType InitiateUploadNewFileRequest::GetRequestType() const { return net::URLFetcher::POST; } bool InitiateUploadNewFileRequest::GetContentData( std::string* upload_content_type, std::string* upload_content) { *upload_content_type = kContentTypeApplicationJson; base::DictionaryValue root; root.SetString("title", title_); // Fill parent link. { scoped_ptr parent(new base::DictionaryValue); parent->SetString("kind", kParentLinkKind); parent->SetString("id", parent_resource_id_); scoped_ptr parents(new base::ListValue); parents->Append(parent.release()); root.Set("parents", parents.release()); } base::JSONWriter::Write(&root, upload_content); DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; } //===================== InitiateUploadExistingFileRequest ==================== InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const DriveApiUrlGenerator& url_generator, const std::string& content_type, int64 content_length, const std::string& resource_id, const std::string& etag, const InitiateUploadCallback& callback) : InitiateUploadRequestBase(runner, url_request_context_getter, callback, content_type, content_length), url_generator_(url_generator), resource_id_(resource_id), etag_(etag) { } InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {} GURL InitiateUploadExistingFileRequest::GetURL() const { return url_generator_.GetInitiateUploadExistingFileUrl(resource_id_); } net::URLFetcher::RequestType InitiateUploadExistingFileRequest::GetRequestType() const { return net::URLFetcher::PUT; } std::vector InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const { std::vector headers( InitiateUploadRequestBase::GetExtraRequestHeaders()); headers.push_back(util::GenerateIfMatchHeader(etag_)); return headers; } //============================ ResumeUploadRequest =========================== ResumeUploadRequest::ResumeUploadRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const GURL& upload_location, int64 start_position, int64 end_position, int64 content_length, const std::string& content_type, const base::FilePath& local_file_path, const UploadRangeCallback& callback, const ProgressCallback& progress_callback) : ResumeUploadRequestBase(runner, url_request_context_getter, upload_location, start_position, end_position, content_length, content_type, local_file_path), callback_(callback), progress_callback_(progress_callback) { DCHECK(!callback_.is_null()); } ResumeUploadRequest::~ResumeUploadRequest() {} void ResumeUploadRequest::OnRangeRequestComplete( const UploadRangeResponse& response, scoped_ptr value) { ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass()); } void ResumeUploadRequest::OnURLFetchUploadProgress( const net::URLFetcher* source, int64 current, int64 total) { if (!progress_callback_.is_null()) progress_callback_.Run(current, total); } //========================== GetUploadStatusRequest ========================== GetUploadStatusRequest::GetUploadStatusRequest( RequestSender* runner, net::URLRequestContextGetter* url_request_context_getter, const GURL& upload_url, int64 content_length, const UploadRangeCallback& callback) : GetUploadStatusRequestBase(runner, url_request_context_getter, upload_url, content_length), callback_(callback) { DCHECK(!callback.is_null()); } GetUploadStatusRequest::~GetUploadStatusRequest() {} void GetUploadStatusRequest::OnRangeRequestComplete( const UploadRangeResponse& response, scoped_ptr value) { ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass()); } } // namespace drive } // namespace google_apis