diff options
Diffstat (limited to 'chromium/google_apis/drive/gdata_wapi_requests.cc')
-rw-r--r-- | chromium/google_apis/drive/gdata_wapi_requests.cc | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/chromium/google_apis/drive/gdata_wapi_requests.cc b/chromium/google_apis/drive/gdata_wapi_requests.cc new file mode 100644 index 00000000000..1ae8a95ef08 --- /dev/null +++ b/chromium/google_apis/drive/gdata_wapi_requests.cc @@ -0,0 +1,680 @@ +// 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 "google_apis/drive/gdata_wapi_requests.h" + +#include "base/location.h" +#include "base/sequenced_task_runner.h" +#include "base/task_runner_util.h" +#include "base/values.h" +#include "google_apis/drive/gdata_wapi_parser.h" +#include "google_apis/drive/gdata_wapi_url_generator.h" +#include "google_apis/drive/request_sender.h" +#include "google_apis/drive/request_util.h" +#include "third_party/libxml/chromium/libxml_utils.h" + +using net::URLFetcher; + +namespace google_apis { + +namespace { + +// Parses the JSON value to ResourceList. +scoped_ptr<ResourceList> ParseResourceListOnBlockingPool( + scoped_ptr<base::Value> value) { + DCHECK(value); + + return ResourceList::ExtractAndParse(*value); +} + +// Runs |callback| with |error| and |resource_list|, but replace the error code +// with GDATA_PARSE_ERROR, if there was a parsing error. +void DidParseResourceListOnBlockingPool( + const GetResourceListCallback& callback, + GDataErrorCode error, + scoped_ptr<ResourceList> resource_list) { + DCHECK(!callback.is_null()); + + // resource_list being NULL indicates there was a parsing error. + if (!resource_list) + error = GDATA_PARSE_ERROR; + + callback.Run(error, resource_list.Pass()); +} + +// Parses the JSON value to ResourceList on the blocking pool and runs +// |callback| on the UI thread once parsing is done. +void ParseResourceListAndRun( + scoped_refptr<base::TaskRunner> blocking_task_runner, + const GetResourceListCallback& callback, + GDataErrorCode error, + scoped_ptr<base::Value> value) { + DCHECK(!callback.is_null()); + + if (!value) { + callback.Run(error, scoped_ptr<ResourceList>()); + return; + } + + base::PostTaskAndReplyWithResult( + blocking_task_runner, + FROM_HERE, + base::Bind(&ParseResourceListOnBlockingPool, base::Passed(&value)), + base::Bind(&DidParseResourceListOnBlockingPool, callback, error)); +} + +// Parses the JSON value to AccountMetadata and runs |callback| on the UI +// thread once parsing is done. +void ParseAccounetMetadataAndRun(const GetAccountMetadataCallback& callback, + GDataErrorCode error, + scoped_ptr<base::Value> value) { + DCHECK(!callback.is_null()); + + if (!value) { + callback.Run(error, scoped_ptr<AccountMetadata>()); + return; + } + + // Parsing AccountMetadata is cheap enough to do on UI thread. + scoped_ptr<AccountMetadata> entry = + google_apis::AccountMetadata::CreateFrom(*value); + if (!entry) { + callback.Run(GDATA_PARSE_ERROR, scoped_ptr<AccountMetadata>()); + return; + } + + callback.Run(error, entry.Pass()); +} + +// Parses the |value| to ResourceEntry with error handling. +// This is designed to be used for ResumeUploadRequest and +// GetUploadStatusRequest. +scoped_ptr<ResourceEntry> ParseResourceEntry(scoped_ptr<base::Value> value) { + scoped_ptr<ResourceEntry> entry; + if (value.get()) { + entry = ResourceEntry::ExtractAndParse(*value); + + // Note: |value| may be NULL, in particular if the callback is for a + // failure. + if (!entry.get()) + LOG(WARNING) << "Invalid entry received on upload."; + } + + return entry.Pass(); +} + +// Extracts the open link url from the JSON Feed. Used by AuthorizeApp(). +void ParseOpenLinkAndRun(const std::string& app_id, + const AuthorizeAppCallback& callback, + GDataErrorCode error, + scoped_ptr<base::Value> value) { + DCHECK(!callback.is_null()); + + if (!value) { + callback.Run(error, GURL()); + return; + } + + // Parsing ResourceEntry is cheap enough to do on UI thread. + scoped_ptr<ResourceEntry> resource_entry = ParseResourceEntry(value.Pass()); + if (!resource_entry) { + callback.Run(GDATA_PARSE_ERROR, GURL()); + return; + } + + // Look for the link to open the file with the app with |app_id|. + const ScopedVector<Link>& resource_links = resource_entry->links(); + GURL open_link; + for (size_t i = 0; i < resource_links.size(); ++i) { + const Link& link = *resource_links[i]; + if (link.type() == Link::LINK_OPEN_WITH && link.app_id() == app_id) { + open_link = link.href(); + break; + } + } + + if (open_link.is_empty()) + error = GDATA_OTHER_ERROR; + + callback.Run(error, open_link); +} + +} // namespace + +//============================ GetResourceListRequest ======================== + +GetResourceListRequest::GetResourceListRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const GURL& override_url, + int64 start_changestamp, + const std::string& search_string, + const std::string& directory_resource_id, + const GetResourceListCallback& callback) + : GetDataRequest( + sender, + base::Bind(&ParseResourceListAndRun, + make_scoped_refptr(sender->blocking_task_runner()), + callback)), + url_generator_(url_generator), + override_url_(override_url), + start_changestamp_(start_changestamp), + search_string_(search_string), + directory_resource_id_(directory_resource_id) { + DCHECK(!callback.is_null()); +} + +GetResourceListRequest::~GetResourceListRequest() {} + +GURL GetResourceListRequest::GetURL() const { + return url_generator_.GenerateResourceListUrl(override_url_, + start_changestamp_, + search_string_, + directory_resource_id_); +} + +//============================ SearchByTitleRequest ========================== + +SearchByTitleRequest::SearchByTitleRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const std::string& title, + const std::string& directory_resource_id, + const GetResourceListCallback& callback) + : GetDataRequest( + sender, + base::Bind(&ParseResourceListAndRun, + make_scoped_refptr(sender->blocking_task_runner()), + callback)), + url_generator_(url_generator), + title_(title), + directory_resource_id_(directory_resource_id) { + DCHECK(!callback.is_null()); +} + +SearchByTitleRequest::~SearchByTitleRequest() {} + +GURL SearchByTitleRequest::GetURL() const { + return url_generator_.GenerateSearchByTitleUrl( + title_, directory_resource_id_); +} + +//============================ GetResourceEntryRequest ======================= + +GetResourceEntryRequest::GetResourceEntryRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const std::string& resource_id, + const GURL& embed_origin, + const GetDataCallback& callback) + : GetDataRequest(sender, callback), + url_generator_(url_generator), + resource_id_(resource_id), + embed_origin_(embed_origin) { + DCHECK(!callback.is_null()); +} + +GetResourceEntryRequest::~GetResourceEntryRequest() {} + +GURL GetResourceEntryRequest::GetURL() const { + return url_generator_.GenerateEditUrlWithEmbedOrigin( + resource_id_, embed_origin_); +} + +//========================= GetAccountMetadataRequest ======================== + +GetAccountMetadataRequest::GetAccountMetadataRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const GetAccountMetadataCallback& callback, + bool include_installed_apps) + : GetDataRequest(sender, + base::Bind(&ParseAccounetMetadataAndRun, callback)), + url_generator_(url_generator), + include_installed_apps_(include_installed_apps) { + DCHECK(!callback.is_null()); +} + +GetAccountMetadataRequest::~GetAccountMetadataRequest() {} + +GURL GetAccountMetadataRequest::GetURL() const { + return url_generator_.GenerateAccountMetadataUrl(include_installed_apps_); +} + +//=========================== DeleteResourceRequest ========================== + +DeleteResourceRequest::DeleteResourceRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const EntryActionCallback& callback, + const std::string& resource_id, + const std::string& etag) + : EntryActionRequest(sender, callback), + url_generator_(url_generator), + resource_id_(resource_id), + etag_(etag) { + DCHECK(!callback.is_null()); +} + +DeleteResourceRequest::~DeleteResourceRequest() {} + +GURL DeleteResourceRequest::GetURL() const { + return url_generator_.GenerateEditUrl(resource_id_); +} + +URLFetcher::RequestType DeleteResourceRequest::GetRequestType() const { + return URLFetcher::DELETE_REQUEST; +} + +std::vector<std::string> +DeleteResourceRequest::GetExtraRequestHeaders() const { + std::vector<std::string> headers; + headers.push_back(util::GenerateIfMatchHeader(etag_)); + return headers; +} + +//========================== CreateDirectoryRequest ========================== + +CreateDirectoryRequest::CreateDirectoryRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const GetDataCallback& callback, + const std::string& parent_resource_id, + const std::string& directory_title) + : GetDataRequest(sender, callback), + url_generator_(url_generator), + parent_resource_id_(parent_resource_id), + directory_title_(directory_title) { + DCHECK(!callback.is_null()); +} + +CreateDirectoryRequest::~CreateDirectoryRequest() {} + +GURL CreateDirectoryRequest::GetURL() const { + return url_generator_.GenerateContentUrl(parent_resource_id_); +} + +URLFetcher::RequestType +CreateDirectoryRequest::GetRequestType() const { + return URLFetcher::POST; +} + +bool CreateDirectoryRequest::GetContentData(std::string* upload_content_type, + std::string* upload_content) { + upload_content_type->assign("application/atom+xml"); + XmlWriter xml_writer; + xml_writer.StartWriting(); + xml_writer.StartElement("entry"); + xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom"); + + xml_writer.StartElement("category"); + xml_writer.AddAttribute("scheme", + "http://schemas.google.com/g/2005#kind"); + xml_writer.AddAttribute("term", + "http://schemas.google.com/docs/2007#folder"); + xml_writer.EndElement(); // Ends "category" element. + + xml_writer.WriteElement("title", directory_title_); + + xml_writer.EndElement(); // Ends "entry" element. + xml_writer.StopWriting(); + upload_content->assign(xml_writer.GetWrittenString()); + DVLOG(1) << "CreateDirectory data: " << *upload_content_type << ", [" + << *upload_content << "]"; + return true; +} + +//=========================== RenameResourceRequest ========================== + +RenameResourceRequest::RenameResourceRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const EntryActionCallback& callback, + const std::string& resource_id, + const std::string& new_title) + : EntryActionRequest(sender, callback), + url_generator_(url_generator), + resource_id_(resource_id), + new_title_(new_title) { + DCHECK(!callback.is_null()); +} + +RenameResourceRequest::~RenameResourceRequest() {} + +URLFetcher::RequestType RenameResourceRequest::GetRequestType() const { + return URLFetcher::PUT; +} + +std::vector<std::string> +RenameResourceRequest::GetExtraRequestHeaders() const { + std::vector<std::string> headers; + headers.push_back(util::kIfMatchAllHeader); + return headers; +} + +GURL RenameResourceRequest::GetURL() const { + return url_generator_.GenerateEditUrl(resource_id_); +} + +bool RenameResourceRequest::GetContentData(std::string* upload_content_type, + std::string* upload_content) { + upload_content_type->assign("application/atom+xml"); + XmlWriter xml_writer; + xml_writer.StartWriting(); + xml_writer.StartElement("entry"); + xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom"); + + xml_writer.WriteElement("title", new_title_); + + xml_writer.EndElement(); // Ends "entry" element. + xml_writer.StopWriting(); + upload_content->assign(xml_writer.GetWrittenString()); + DVLOG(1) << "RenameResourceRequest data: " << *upload_content_type << ", [" + << *upload_content << "]"; + return true; +} + +//=========================== AuthorizeAppRequest ========================== + +AuthorizeAppRequest::AuthorizeAppRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const AuthorizeAppCallback& callback, + const std::string& resource_id, + const std::string& app_id) + : GetDataRequest(sender, + base::Bind(&ParseOpenLinkAndRun, app_id, callback)), + url_generator_(url_generator), + resource_id_(resource_id), + app_id_(app_id) { + DCHECK(!callback.is_null()); +} + +AuthorizeAppRequest::~AuthorizeAppRequest() {} + +URLFetcher::RequestType AuthorizeAppRequest::GetRequestType() const { + return URLFetcher::PUT; +} + +std::vector<std::string> +AuthorizeAppRequest::GetExtraRequestHeaders() const { + std::vector<std::string> headers; + headers.push_back(util::kIfMatchAllHeader); + return headers; +} + +bool AuthorizeAppRequest::GetContentData(std::string* upload_content_type, + std::string* upload_content) { + upload_content_type->assign("application/atom+xml"); + XmlWriter xml_writer; + xml_writer.StartWriting(); + xml_writer.StartElement("entry"); + xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom"); + xml_writer.AddAttribute("xmlns:docs", "http://schemas.google.com/docs/2007"); + xml_writer.WriteElement("docs:authorizedApp", app_id_); + + xml_writer.EndElement(); // Ends "entry" element. + xml_writer.StopWriting(); + upload_content->assign(xml_writer.GetWrittenString()); + DVLOG(1) << "AuthorizeAppRequest data: " << *upload_content_type << ", [" + << *upload_content << "]"; + return true; +} + +GURL AuthorizeAppRequest::GetURL() const { + return url_generator_.GenerateEditUrl(resource_id_); +} + +//======================= AddResourceToDirectoryRequest ====================== + +AddResourceToDirectoryRequest::AddResourceToDirectoryRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const EntryActionCallback& callback, + const std::string& parent_resource_id, + const std::string& resource_id) + : EntryActionRequest(sender, callback), + url_generator_(url_generator), + parent_resource_id_(parent_resource_id), + resource_id_(resource_id) { + DCHECK(!callback.is_null()); +} + +AddResourceToDirectoryRequest::~AddResourceToDirectoryRequest() {} + +GURL AddResourceToDirectoryRequest::GetURL() const { + return url_generator_.GenerateContentUrl(parent_resource_id_); +} + +URLFetcher::RequestType +AddResourceToDirectoryRequest::GetRequestType() const { + return URLFetcher::POST; +} + +bool AddResourceToDirectoryRequest::GetContentData( + std::string* upload_content_type, std::string* upload_content) { + upload_content_type->assign("application/atom+xml"); + XmlWriter xml_writer; + xml_writer.StartWriting(); + xml_writer.StartElement("entry"); + xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom"); + + xml_writer.WriteElement( + "id", url_generator_.GenerateEditUrlWithoutParams(resource_id_).spec()); + + xml_writer.EndElement(); // Ends "entry" element. + xml_writer.StopWriting(); + upload_content->assign(xml_writer.GetWrittenString()); + DVLOG(1) << "AddResourceToDirectoryRequest data: " << *upload_content_type + << ", [" << *upload_content << "]"; + return true; +} + +//==================== RemoveResourceFromDirectoryRequest ==================== + +RemoveResourceFromDirectoryRequest::RemoveResourceFromDirectoryRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const EntryActionCallback& callback, + const std::string& parent_resource_id, + const std::string& document_resource_id) + : EntryActionRequest(sender, callback), + url_generator_(url_generator), + resource_id_(document_resource_id), + parent_resource_id_(parent_resource_id) { + DCHECK(!callback.is_null()); +} + +RemoveResourceFromDirectoryRequest::~RemoveResourceFromDirectoryRequest() { +} + +GURL RemoveResourceFromDirectoryRequest::GetURL() const { + return url_generator_.GenerateResourceUrlForRemoval( + parent_resource_id_, resource_id_); +} + +URLFetcher::RequestType +RemoveResourceFromDirectoryRequest::GetRequestType() const { + return URLFetcher::DELETE_REQUEST; +} + +std::vector<std::string> +RemoveResourceFromDirectoryRequest::GetExtraRequestHeaders() const { + std::vector<std::string> headers; + headers.push_back(util::kIfMatchAllHeader); + return headers; +} + +//======================= InitiateUploadNewFileRequest ======================= + +InitiateUploadNewFileRequest::InitiateUploadNewFileRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const InitiateUploadCallback& callback, + const std::string& content_type, + int64 content_length, + const std::string& parent_resource_id, + const std::string& title) + : InitiateUploadRequestBase(sender, 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_.GenerateInitiateUploadNewFileUrl(parent_resource_id_); +} + +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->assign("application/atom+xml"); + XmlWriter xml_writer; + xml_writer.StartWriting(); + xml_writer.StartElement("entry"); + xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom"); + xml_writer.AddAttribute("xmlns:docs", + "http://schemas.google.com/docs/2007"); + xml_writer.WriteElement("title", title_); + xml_writer.EndElement(); // Ends "entry" element. + xml_writer.StopWriting(); + upload_content->assign(xml_writer.GetWrittenString()); + DVLOG(1) << "InitiateUploadNewFile: " << *upload_content_type << ", [" + << *upload_content << "]"; + return true; +} + +//===================== InitiateUploadExistingFileRequest ==================== + +InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const InitiateUploadCallback& callback, + const std::string& content_type, + int64 content_length, + const std::string& resource_id, + const std::string& etag) + : InitiateUploadRequestBase(sender, callback, content_type, content_length), + url_generator_(url_generator), + resource_id_(resource_id), + etag_(etag) { +} + +InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {} + +GURL InitiateUploadExistingFileRequest::GetURL() const { + return url_generator_.GenerateInitiateUploadExistingFileUrl(resource_id_); +} + +net::URLFetcher::RequestType +InitiateUploadExistingFileRequest::GetRequestType() const { + return net::URLFetcher::PUT; +} + +bool InitiateUploadExistingFileRequest::GetContentData( + std::string* upload_content_type, + std::string* upload_content) { + // According to the document there is no need to send the content-type. + // However, the server would return 500 server error without the + // content-type. + // As its workaround, send "text/plain" content-type here. + *upload_content_type = "text/plain"; + *upload_content = ""; + return true; +} + +std::vector<std::string> +InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const { + std::vector<std::string> headers( + InitiateUploadRequestBase::GetExtraRequestHeaders()); + headers.push_back(util::GenerateIfMatchHeader(etag_)); + return headers; +} + +//============================ ResumeUploadRequest =========================== + +ResumeUploadRequest::ResumeUploadRequest( + RequestSender* sender, + const UploadRangeCallback& callback, + const ProgressCallback& progress_callback, + const GURL& upload_location, + int64 start_position, + int64 end_position, + int64 content_length, + const std::string& content_type, + const base::FilePath& local_file_path) + : ResumeUploadRequestBase(sender, + 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<base::Value> value) { + callback_.Run(response, ParseResourceEntry(value.Pass())); +} + +void ResumeUploadRequest::OnURLFetchUploadProgress( + const URLFetcher* source, int64 current, int64 total) { + if (!progress_callback_.is_null()) + progress_callback_.Run(current, total); +} + +//========================== GetUploadStatusRequest ========================== + +GetUploadStatusRequest::GetUploadStatusRequest( + RequestSender* sender, + const UploadRangeCallback& callback, + const GURL& upload_url, + int64 content_length) + : GetUploadStatusRequestBase(sender, upload_url, content_length), + callback_(callback) { + DCHECK(!callback.is_null()); +} + +GetUploadStatusRequest::~GetUploadStatusRequest() {} + +void GetUploadStatusRequest::OnRangeRequestComplete( + const UploadRangeResponse& response, scoped_ptr<base::Value> value) { + callback_.Run(response, ParseResourceEntry(value.Pass())); +} + +//========================== DownloadFileRequest ========================== + +DownloadFileRequest::DownloadFileRequest( + RequestSender* sender, + const GDataWapiUrlGenerator& url_generator, + const DownloadActionCallback& download_action_callback, + const GetContentCallback& get_content_callback, + const ProgressCallback& progress_callback, + const std::string& resource_id, + const base::FilePath& output_file_path) + : DownloadFileRequestBase( + sender, + download_action_callback, + get_content_callback, + progress_callback, + url_generator.GenerateDownloadFileUrl(resource_id), + output_file_path) { +} + +DownloadFileRequest::~DownloadFileRequest() { +} + +} // namespace google_apis |