diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/google_apis/drive | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/google_apis/drive')
27 files changed, 821 insertions, 4003 deletions
diff --git a/chromium/google_apis/drive/auth_service.cc b/chromium/google_apis/drive/auth_service.cc index 18623686f94..51229f92b6a 100644 --- a/chromium/google_apis/drive/auth_service.cc +++ b/chromium/google_apis/drive/auth_service.cc @@ -58,7 +58,8 @@ AuthRequest::AuthRequest( net::URLRequestContextGetter* url_request_context_getter, const AuthStatusCallback& callback, const std::vector<std::string>& scopes) - : callback_(callback) { + : OAuth2TokenService::Consumer("auth_service"), + callback_(callback) { DCHECK(!callback_.is_null()); request_ = oauth2_token_service-> StartRequestWithContext( diff --git a/chromium/google_apis/drive/base_requests.cc b/chromium/google_apis/drive/base_requests.cc index be64f783c24..0c1a238057e 100644 --- a/chromium/google_apis/drive/base_requests.cc +++ b/chromium/google_apis/drive/base_requests.cc @@ -358,6 +358,7 @@ void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) { const char kErrorMessageKey[] = "message"; const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded"; const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded"; + const char kErrorReasonQuotaExceeded[] = "quotaExceeded"; scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data())); base::DictionaryValue* dictionary = NULL; @@ -380,6 +381,8 @@ void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) { if (reason == kErrorReasonRateLimitExceeded || reason == kErrorReasonUserRateLimitExceeded) error_code_ = HTTP_SERVICE_UNAVAILABLE; + if (reason == kErrorReasonQuotaExceeded) + error_code_ = GDATA_NO_SPACE; } } } diff --git a/chromium/google_apis/drive/base_requests_unittest.cc b/chromium/google_apis/drive/base_requests_unittest.cc index 3032d2abb37..f3a97c19156 100644 --- a/chromium/google_apis/drive/base_requests_unittest.cc +++ b/chromium/google_apis/drive/base_requests_unittest.cc @@ -115,7 +115,7 @@ TEST_F(BaseRequestsTest, ParseValidJson) { base::Bind(test_util::CreateCopyResultCallback(&json))); base::RunLoop().RunUntilIdle(); - DictionaryValue* root_dict = NULL; + base::DictionaryValue* root_dict = NULL; ASSERT_TRUE(json); ASSERT_TRUE(json->GetAsDictionary(&root_dict)); diff --git a/chromium/google_apis/drive/drive_api_parser.cc b/chromium/google_apis/drive/drive_api_parser.cc index 4b05e8b5844..c22070eb458 100644 --- a/chromium/google_apis/drive/drive_api_parser.cc +++ b/chromium/google_apis/drive/drive_api_parser.cc @@ -38,6 +38,28 @@ bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) { return true; } +// Converts |value| to |result|. +bool GetParentsFromValue(const base::Value* value, + std::vector<ParentReference>* result) { + DCHECK(value); + DCHECK(result); + + const base::ListValue* list_value = NULL; + if (!value->GetAsList(&list_value)) + return false; + + base::JSONValueConverter<ParentReference> converter; + result->resize(list_value->GetSize()); + for (size_t i = 0; i < list_value->GetSize(); ++i) { + const base::Value* parent_value = NULL; + if (!list_value->Get(i, &parent_value) || + !converter.Convert(*parent_value, &(*result)[i])) + return false; + } + + return true; +} + // Converts |value| to |result|. The key of |value| is app_id, and its value // is URL to open the resource on the web app. bool GetOpenWithLinksFromDictionaryValue( @@ -75,7 +97,6 @@ bool GetOpenWithLinksFromDictionaryValue( const char kKind[] = "kind"; const char kId[] = "id"; const char kETag[] = "etag"; -const char kSelfLink[] = "selfLink"; const char kItems[] = "items"; const char kLargestChangeId[] = "largestChangeId"; @@ -97,16 +118,15 @@ const char kIconUrl[] = "iconUrl"; const char kAppKind[] = "drive#app"; const char kName[] = "name"; const char kObjectType[] = "objectType"; +const char kProductId[] = "productId"; const char kSupportsCreate[] = "supportsCreate"; -const char kSupportsImport[] = "supportsImport"; -const char kInstalled[] = "installed"; -const char kAuthorized[] = "authorized"; -const char kProductUrl[] = "productUrl"; +const char kRemovable[] = "removable"; const char kPrimaryMimeTypes[] = "primaryMimeTypes"; const char kSecondaryMimeTypes[] = "secondaryMimeTypes"; const char kPrimaryFileExtensions[] = "primaryFileExtensions"; const char kSecondaryFileExtensions[] = "secondaryFileExtensions"; const char kIcons[] = "icons"; +const char kCreateUrl[] = "createUrl"; // Apps List // https://developers.google.com/drive/v2/reference/apps/list @@ -116,7 +136,6 @@ const char kAppListKind[] = "drive#appList"; // https://developers.google.com/drive/v2/reference/parents const char kParentReferenceKind[] = "drive#parentReference"; const char kParentLink[] = "parentLink"; -const char kIsRoot[] = "isRoot"; // File Resource // https://developers.google.com/drive/v2/reference/files @@ -124,29 +143,20 @@ const char kFileKind[] = "drive#file"; const char kTitle[] = "title"; const char kMimeType[] = "mimeType"; const char kCreatedDate[] = "createdDate"; +const char kModificationDate[] = "modificationDate"; const char kModifiedDate[] = "modifiedDate"; -const char kModifiedByMeDate[] = "modifiedByMeDate"; const char kLastViewedByMeDate[] = "lastViewedByMeDate"; const char kSharedWithMeDate[] = "sharedWithMeDate"; -const char kDownloadUrl[] = "downloadUrl"; -const char kFileExtension[] = "fileExtension"; const char kMd5Checksum[] = "md5Checksum"; const char kFileSize[] = "fileSize"; const char kAlternateLink[] = "alternateLink"; -const char kEmbedLink[] = "embedLink"; const char kParents[] = "parents"; -const char kThumbnailLink[] = "thumbnailLink"; -const char kWebContentLink[] = "webContentLink"; const char kOpenWithLinks[] = "openWithLinks"; const char kLabels[] = "labels"; const char kImageMediaMetadata[] = "imageMediaMetadata"; const char kShared[] = "shared"; // These 5 flags are defined under |labels|. -const char kLabelStarred[] = "starred"; -const char kLabelHidden[] = "hidden"; const char kLabelTrashed[] = "trashed"; -const char kLabelRestricted[] = "restricted"; -const char kLabelViewed[] = "viewed"; // These 3 flags are defined under |imageMediaMetadata|. const char kImageMediaMetadataWidth[] = "width"; const char kImageMediaMetadataHeight[] = "height"; @@ -157,7 +167,6 @@ const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder"; // Files List // https://developers.google.com/drive/v2/reference/files/list const char kFileListKind[] = "drive#fileList"; -const char kNextPageToken[] = "nextPageToken"; const char kNextLink[] = "nextLink"; // Change Resource @@ -299,9 +308,7 @@ bool DriveAppIcon::GetIconCategory(const base::StringPiece& category, AppResource::AppResource() : supports_create_(false), - supports_import_(false), - installed_(false), - authorized_(false) { + removable_(false) { } AppResource::~AppResource() {} @@ -312,13 +319,9 @@ void AppResource::RegisterJSONConverter( converter->RegisterStringField(kId, &AppResource::application_id_); converter->RegisterStringField(kName, &AppResource::name_); converter->RegisterStringField(kObjectType, &AppResource::object_type_); + converter->RegisterStringField(kProductId, &AppResource::product_id_); converter->RegisterBoolField(kSupportsCreate, &AppResource::supports_create_); - converter->RegisterBoolField(kSupportsImport, &AppResource::supports_import_); - converter->RegisterBoolField(kInstalled, &AppResource::installed_); - converter->RegisterBoolField(kAuthorized, &AppResource::authorized_); - converter->RegisterCustomField<GURL>(kProductUrl, - &AppResource::product_url_, - GetGURLFromString); + converter->RegisterBoolField(kRemovable, &AppResource::removable_); converter->RegisterRepeatedString(kPrimaryMimeTypes, &AppResource::primary_mimetypes_); converter->RegisterRepeatedString(kSecondaryMimeTypes, @@ -328,6 +331,9 @@ void AppResource::RegisterJSONConverter( converter->RegisterRepeatedString(kSecondaryFileExtensions, &AppResource::secondary_file_extensions_); converter->RegisterRepeatedMessage(kIcons, &AppResource::icons_); + converter->RegisterCustomField<GURL>(kCreateUrl, + &AppResource::create_url_, + GetGURLFromString); } // static @@ -386,7 +392,7 @@ bool AppList::Parse(const base::Value& value) { //////////////////////////////////////////////////////////////////////////////// // ParentReference implementation -ParentReference::ParentReference() : is_root_(false) {} +ParentReference::ParentReference() {} ParentReference::~ParentReference() {} @@ -397,7 +403,6 @@ void ParentReference::RegisterJSONConverter( converter->RegisterCustomField<GURL>(kParentLink, &ParentReference::parent_link_, GetGURLFromString); - converter->RegisterBoolField(kIsRoot, &ParentReference::is_root_); } // static @@ -433,9 +438,6 @@ void FileResource::RegisterJSONConverter( base::JSONValueConverter<FileResource>* converter) { converter->RegisterStringField(kId, &FileResource::file_id_); converter->RegisterStringField(kETag, &FileResource::etag_); - converter->RegisterCustomField<GURL>(kSelfLink, - &FileResource::self_link_, - GetGURLFromString); converter->RegisterStringField(kTitle, &FileResource::title_); converter->RegisterStringField(kMimeType, &FileResource::mime_type_); converter->RegisterNestedField(kLabels, &FileResource::labels_); @@ -450,10 +452,6 @@ void FileResource::RegisterJSONConverter( &FileResource::modified_date_, &util::GetTimeFromString); converter->RegisterCustomField<base::Time>( - kModifiedByMeDate, - &FileResource::modified_by_me_date_, - &util::GetTimeFromString); - converter->RegisterCustomField<base::Time>( kLastViewedByMeDate, &FileResource::last_viewed_by_me_date_, &util::GetTimeFromString); @@ -462,11 +460,6 @@ void FileResource::RegisterJSONConverter( &FileResource::shared_with_me_date_, &util::GetTimeFromString); converter->RegisterBoolField(kShared, &FileResource::shared_); - converter->RegisterCustomField<GURL>(kDownloadUrl, - &FileResource::download_url_, - GetGURLFromString); - converter->RegisterStringField(kFileExtension, - &FileResource::file_extension_); converter->RegisterStringField(kMd5Checksum, &FileResource::md5_checksum_); converter->RegisterCustomField<int64>(kFileSize, &FileResource::file_size_, @@ -474,17 +467,10 @@ void FileResource::RegisterJSONConverter( converter->RegisterCustomField<GURL>(kAlternateLink, &FileResource::alternate_link_, GetGURLFromString); - converter->RegisterCustomField<GURL>(kEmbedLink, - &FileResource::embed_link_, - GetGURLFromString); - converter->RegisterRepeatedMessage<ParentReference>(kParents, - &FileResource::parents_); - converter->RegisterCustomField<GURL>(kThumbnailLink, - &FileResource::thumbnail_link_, - GetGURLFromString); - converter->RegisterCustomField<GURL>(kWebContentLink, - &FileResource::web_content_link_, - GetGURLFromString); + converter->RegisterCustomValueField<std::vector<ParentReference> >( + kParents, + &FileResource::parents_, + GetParentsFromValue); converter->RegisterCustomValueField<std::vector<OpenWithLink> >( kOpenWithLinks, &FileResource::open_with_links_, @@ -524,8 +510,6 @@ FileList::~FileList() {} // static void FileList::RegisterJSONConverter( base::JSONValueConverter<FileList>* converter) { - converter->RegisterStringField(kETag, &FileList::etag_); - converter->RegisterStringField(kNextPageToken, &FileList::next_page_token_); converter->RegisterCustomField<GURL>(kNextLink, &FileList::next_link_, GetGURLFromString); @@ -574,6 +558,9 @@ void ChangeResource::RegisterJSONConverter( converter->RegisterBoolField(kDeleted, &ChangeResource::deleted_); converter->RegisterCustomValueField(kFile, &ChangeResource::file_, &CreateFileResourceFromValue); + converter->RegisterCustomField<base::Time>( + kModificationDate, &ChangeResource::modification_date_, + &util::GetTimeFromString); } // static @@ -606,8 +593,6 @@ ChangeList::~ChangeList() {} // static void ChangeList::RegisterJSONConverter( base::JSONValueConverter<ChangeList>* converter) { - converter->RegisterStringField(kETag, &ChangeList::etag_); - converter->RegisterStringField(kNextPageToken, &ChangeList::next_page_token_); converter->RegisterCustomField<GURL>(kNextLink, &ChangeList::next_link_, GetGURLFromString); @@ -646,23 +631,14 @@ bool ChangeList::Parse(const base::Value& value) { //////////////////////////////////////////////////////////////////////////////// // FileLabels implementation -FileLabels::FileLabels() - : starred_(false), - hidden_(false), - trashed_(false), - restricted_(false), - viewed_(false) {} +FileLabels::FileLabels() : trashed_(false) {} FileLabels::~FileLabels() {} // static void FileLabels::RegisterJSONConverter( base::JSONValueConverter<FileLabels>* converter) { - converter->RegisterBoolField(kLabelStarred, &FileLabels::starred_); - converter->RegisterBoolField(kLabelHidden, &FileLabels::hidden_); converter->RegisterBoolField(kLabelTrashed, &FileLabels::trashed_); - converter->RegisterBoolField(kLabelRestricted, &FileLabels::restricted_); - converter->RegisterBoolField(kLabelViewed, &FileLabels::viewed_); } // static @@ -717,7 +693,6 @@ scoped_ptr<ImageMediaMetadata> ImageMediaMetadata::CreateFrom( } bool ImageMediaMetadata::Parse(const base::Value& value) { - return true; base::JSONValueConverter<ImageMediaMetadata> converter; if (!converter.Convert(value, this)) { LOG(ERROR) << "Unable to parse: Invalid ImageMediaMetadata."; diff --git a/chromium/google_apis/drive/drive_api_parser.h b/chromium/google_apis/drive/drive_api_parser.h index ef02035d595..babb4cdc5c1 100644 --- a/chromium/google_apis/drive/drive_api_parser.h +++ b/chromium/google_apis/drive/drive_api_parser.h @@ -168,21 +168,17 @@ class AppResource { // If empty, application name is used instead. const std::string& object_type() const { return object_type_; } + // Returns the product ID. + const std::string& product_id() const { return product_id_; } + // Returns whether this application supports creating new objects. bool supports_create() const { return supports_create_; } - // Returns whether this application supports importing Google Docs. - bool supports_import() const { return supports_import_; } - - // Returns whether this application is installed. - bool is_installed() const { return installed_; } - - // Returns whether this application is authorized to access data on the - // user's Drive. - bool is_authorized() const { return authorized_; } + // Returns whether this application is removable by apps.delete API. + bool is_removable() const { return removable_; } - // Returns the product URL, e.g. at Chrome Web Store. - const GURL& product_url() const { return product_url_; } + // Returns the create URL, i.e., the URL for opening a new file by the app. + const GURL& create_url() const { return create_url_; } // List of primary mime types supported by this WebApp. Primary status should // trigger this WebApp becoming the default handler of file instances that @@ -226,17 +222,11 @@ class AppResource { void set_object_type(const std::string& object_type) { object_type_ = object_type; } + void set_product_id(const std::string& id) { product_id_ = id; } void set_supports_create(bool supports_create) { supports_create_ = supports_create; } - void set_supports_import(bool supports_import) { - supports_import_ = supports_import; - } - void set_installed(bool installed) { installed_ = installed; } - void set_authorized(bool authorized) { authorized_ = authorized; } - void set_product_url(const GURL& product_url) { - product_url_ = product_url; - } + void set_removable(bool removable) { removable_ = removable; } void set_primary_mimetypes( ScopedVector<std::string> primary_mimetypes) { primary_mimetypes_ = primary_mimetypes.Pass(); @@ -256,6 +246,9 @@ class AppResource { void set_icons(ScopedVector<DriveAppIcon> icons) { icons_ = icons.Pass(); } + void set_create_url(const GURL& url) { + create_url_ = url; + } private: friend class base::internal::RepeatedMessageConverter<AppResource>; @@ -268,11 +261,10 @@ class AppResource { std::string application_id_; std::string name_; std::string object_type_; + std::string product_id_; bool supports_create_; - bool supports_import_; - bool installed_; - bool authorized_; - GURL product_url_; + bool removable_; + GURL create_url_; ScopedVector<std::string> primary_mimetypes_; ScopedVector<std::string> secondary_mimetypes_; ScopedVector<std::string> primary_file_extensions_; @@ -345,27 +337,18 @@ class ParentReference { // Returns the URL for the parent in Drive. const GURL& parent_link() const { return parent_link_; } - // Returns true if the reference is root directory. - bool is_root() const { return is_root_; } - void set_file_id(const std::string& file_id) { file_id_ = file_id; } void set_parent_link(const GURL& parent_link) { parent_link_ = parent_link; } - void set_is_root(bool is_root) { is_root_ = is_root; } private: - friend class base::internal::RepeatedMessageConverter<ParentReference>; - // Parses and initializes data members from content of |value|. // Return false if parsing fails. bool Parse(const base::Value& value); std::string file_id_; GURL parent_link_; - bool is_root_; - - DISALLOW_COPY_AND_ASSIGN(ParentReference); }; // FileLabels represents labels for file or folder. @@ -383,22 +366,10 @@ class FileLabels { // Creates about resource from parsed JSON. static scoped_ptr<FileLabels> CreateFrom(const base::Value& value); - // Whether this file is starred by the user. - bool is_starred() const { return starred_; } - // Whether this file is hidden from the user. - bool is_hidden() const { return hidden_; } // Whether this file has been trashed. bool is_trashed() const { return trashed_; } - // Whether viewers are prevented from downloading this file. - bool is_restricted() const { return restricted_; } - // Whether this file has been viewed by this user. - bool is_viewed() const { return viewed_; } - void set_starred(bool starred) { starred_ = starred; } - void set_hidden(bool hidden) { hidden_ = hidden; } void set_trashed(bool trashed) { trashed_ = trashed; } - void set_restricted(bool restricted) { restricted_ = restricted; } - void set_viewed(bool viewed) { viewed_ = viewed; } private: friend class FileResource; @@ -407,13 +378,7 @@ class FileLabels { // Return false if parsing fails. bool Parse(const base::Value& value); - bool starred_; - bool hidden_; bool trashed_; - bool restricted_; - bool viewed_; - - DISALLOW_COPY_AND_ASSIGN(FileLabels); }; // ImageMediaMetadata represents image metadata for a file. @@ -452,8 +417,6 @@ class ImageMediaMetadata { int width_; int height_; int rotation_; - - DISALLOW_COPY_AND_ASSIGN(ImageMediaMetadata); }; @@ -489,9 +452,6 @@ class FileResource { // Returns ETag for this file. const std::string& etag() const { return etag_; } - // Returns the link to JSON of this file itself. - const GURL& self_link() const { return self_link_; } - // Returns the title of this file. const std::string& title() const { return title_; } @@ -512,9 +472,6 @@ class FileResource { // Returns modified time of this file. const base::Time& modified_date() const { return modified_date_; } - // Returns modification time by the user. - const base::Time& modified_by_me_date() const { return modified_by_me_date_; } - // Returns last access time by the user. const base::Time& last_viewed_by_me_date() const { return last_viewed_by_me_date_; @@ -528,13 +485,6 @@ class FileResource { // Returns the 'shared' attribute of the file. bool shared() const { return shared_; } - // Returns the short-lived download URL for the file. This field exists - // only when the file content is stored in Drive. - const GURL& download_url() const { return download_url_; } - - // Returns the extension part of the filename. - const std::string& file_extension() const { return file_extension_; } - // Returns MD5 checksum of this file. const std::string& md5_checksum() const { return md5_checksum_; } @@ -545,18 +495,8 @@ class FileResource { // E.g. Google Document, Google Spreadsheet. const GURL& alternate_link() const { return alternate_link_; } - // Returns the link for embedding the file. - const GURL& embed_link() const { return embed_link_; } - // Returns parent references (directories) of this file. - const ScopedVector<ParentReference>& parents() const { return parents_; } - - // Returns the link to the file's thumbnail. - const GURL& thumbnail_link() const { return thumbnail_link_; } - - // Returns the link to open its downloadable content, using cookie based - // authentication. - const GURL& web_content_link() const { return web_content_link_; } + const std::vector<ParentReference>& parents() const { return parents_; } // Returns the list of links to open the resource with a web app. const std::vector<OpenWithLink>& open_with_links() const { @@ -569,9 +509,6 @@ class FileResource { void set_etag(const std::string& etag) { etag_ = etag; } - void set_self_link(const GURL& self_link) { - self_link_ = self_link; - } void set_title(const std::string& title) { title_ = title; } @@ -590,9 +527,6 @@ class FileResource { void set_modified_date(const base::Time& modified_date) { modified_date_ = modified_date; } - void set_modified_by_me_date(const base::Time& modified_by_me_date) { - modified_by_me_date_ = modified_by_me_date; - } void set_last_viewed_by_me_date(const base::Time& last_viewed_by_me_date) { last_viewed_by_me_date_ = last_viewed_by_me_date; } @@ -602,12 +536,6 @@ class FileResource { void set_shared(bool shared) { shared_ = shared; } - void set_download_url(const GURL& download_url) { - download_url_ = download_url; - } - void set_file_extension(const std::string& file_extension) { - file_extension_ = file_extension; - } void set_md5_checksum(const std::string& md5_checksum) { md5_checksum_ = md5_checksum; } @@ -617,17 +545,9 @@ class FileResource { void set_alternate_link(const GURL& alternate_link) { alternate_link_ = alternate_link; } - void set_embed_link(const GURL& embed_link) { - embed_link_ = embed_link; - } - void set_parents(ScopedVector<ParentReference> parents) { - parents_ = parents.Pass(); - } - void set_thumbnail_link(const GURL& thumbnail_link) { - thumbnail_link_ = thumbnail_link; - } - void set_web_content_link(const GURL& web_content_link) { - web_content_link_ = web_content_link; + std::vector<ParentReference>* mutable_parents() { return &parents_; } + std::vector<OpenWithLink>* mutable_open_with_links() { + return &open_with_links_; } private: @@ -641,29 +561,20 @@ class FileResource { std::string file_id_; std::string etag_; - GURL self_link_; std::string title_; std::string mime_type_; FileLabels labels_; ImageMediaMetadata image_media_metadata_; base::Time created_date_; base::Time modified_date_; - base::Time modified_by_me_date_; base::Time last_viewed_by_me_date_; base::Time shared_with_me_date_; bool shared_; - GURL download_url_; - std::string file_extension_; std::string md5_checksum_; int64 file_size_; GURL alternate_link_; - GURL embed_link_; - ScopedVector<ParentReference> parents_; - GURL thumbnail_link_; - GURL web_content_link_; + std::vector<ParentReference> parents_; std::vector<OpenWithLink> open_with_links_; - - DISALLOW_COPY_AND_ASSIGN(FileResource); }; // FileList represents a collection of files and folders. @@ -684,32 +595,17 @@ class FileList { // Creates file list from parsed JSON. static scoped_ptr<FileList> CreateFrom(const base::Value& value); - // Returns the ETag of the list. - const std::string& etag() const { return etag_; } - - // Returns the page token for the next page of files, if the list is large - // to fit in one response. If this is empty, there is no more file lists. - const std::string& next_page_token() const { return next_page_token_; } - // Returns a link to the next page of files. The URL includes the next page // token. const GURL& next_link() const { return next_link_; } // Returns a set of files in this list. const ScopedVector<FileResource>& items() const { return items_; } + ScopedVector<FileResource>* mutable_items() { return &items_; } - void set_etag(const std::string& etag) { - etag_ = etag; - } - void set_next_page_token(const std::string& next_page_token) { - next_page_token_ = next_page_token; - } void set_next_link(const GURL& next_link) { next_link_ = next_link; } - void set_items(ScopedVector<FileResource> items) { - items_ = items.Pass(); - } private: friend class DriveAPIParserTest; @@ -719,8 +615,6 @@ class FileList { // Return false if parsing fails. bool Parse(const base::Value& value); - std::string etag_; - std::string next_page_token_; GURL next_link_; ScopedVector<FileResource> items_; @@ -754,6 +648,10 @@ class ChangeResource { // Returns FileResource of the file which the change refers to. const FileResource* file() const { return file_.get(); } + FileResource* mutable_file() { return file_.get(); } + + // Returns the time of this modification. + const base::Time& modification_date() const { return modification_date_; } void set_change_id(int64 change_id) { change_id_ = change_id; @@ -767,6 +665,9 @@ class ChangeResource { void set_file(scoped_ptr<FileResource> file) { file_ = file.Pass(); } + void set_modification_date(const base::Time& modification_date) { + modification_date_ = modification_date; + } private: friend class base::internal::RepeatedMessageConverter<ChangeResource>; @@ -780,6 +681,7 @@ class ChangeResource { std::string file_id_; bool deleted_; scoped_ptr<FileResource> file_; + base::Time modification_date_; DISALLOW_COPY_AND_ASSIGN(ChangeResource); }; @@ -802,13 +704,6 @@ class ChangeList { // Creates change list from parsed JSON. static scoped_ptr<ChangeList> CreateFrom(const base::Value& value); - // Returns the ETag of the list. - const std::string& etag() const { return etag_; } - - // Returns the page token for the next page of files, if the list is large - // to fit in one response. If this is empty, there is no more file lists. - const std::string& next_page_token() const { return next_page_token_; } - // Returns a link to the next page of files. The URL includes the next page // token. const GURL& next_link() const { return next_link_; } @@ -818,22 +713,14 @@ class ChangeList { // Returns a set of changes in this list. const ScopedVector<ChangeResource>& items() const { return items_; } + ScopedVector<ChangeResource>* mutable_items() { return &items_; } - void set_etag(const std::string& etag) { - etag_ = etag; - } - void set_next_page_token(const std::string& next_page_token) { - next_page_token_ = next_page_token; - } void set_next_link(const GURL& next_link) { next_link_ = next_link; } void set_largest_change_id(int64 largest_change_id) { largest_change_id_ = largest_change_id; } - void set_items(ScopedVector<ChangeResource> items) { - items_ = items.Pass(); - } private: friend class DriveAPIParserTest; @@ -843,8 +730,6 @@ class ChangeList { // Return false if parsing fails. bool Parse(const base::Value& value); - std::string etag_; - std::string next_page_token_; GURL next_link_; int64 largest_change_id_; ScopedVector<ChangeResource> items_; diff --git a/chromium/google_apis/drive/drive_api_parser_unittest.cc b/chromium/google_apis/drive/drive_api_parser_unittest.cc index 0960b275bf5..6f9ee65e109 100644 --- a/chromium/google_apis/drive/drive_api_parser_unittest.cc +++ b/chromium/google_apis/drive/drive_api_parser_unittest.cc @@ -50,12 +50,8 @@ TEST(DriveAPIParserTest, AppListParser) { EXPECT_EQ("Drive app 1", app1.name()); EXPECT_EQ("", app1.object_type()); EXPECT_TRUE(app1.supports_create()); - EXPECT_TRUE(app1.supports_import()); - EXPECT_TRUE(app1.is_installed()); - EXPECT_FALSE(app1.is_authorized()); - EXPECT_EQ("https://chrome.google.com/webstore/detail/" - "abcdefghabcdefghabcdefghabcdefgh", - app1.product_url().spec()); + EXPECT_TRUE(app1.is_removable()); + EXPECT_EQ("abcdefghabcdefghabcdefghabcdefgh", app1.product_id()); ASSERT_EQ(1U, app1.primary_mimetypes().size()); EXPECT_EQ("application/vnd.google-apps.drive-sdk.123456788192", @@ -82,18 +78,16 @@ TEST(DriveAPIParserTest, AppListParser) { EXPECT_EQ(16, icon6.icon_side_length()); EXPECT_EQ("http://www.example.com/ds16.png", icon6.icon_url().spec()); + EXPECT_EQ("https://www.example.com/createForApp1", app1.create_url().spec()); + // Check Drive app 2 const AppResource& app2 = *applist->items()[1]; EXPECT_EQ("876543210000", app2.application_id()); EXPECT_EQ("Drive app 2", app2.name()); EXPECT_EQ("", app2.object_type()); EXPECT_FALSE(app2.supports_create()); - EXPECT_FALSE(app2.supports_import()); - EXPECT_TRUE(app2.is_installed()); - EXPECT_FALSE(app2.is_authorized()); - EXPECT_EQ("https://chrome.google.com/webstore/detail/" - "hgfedcbahgfedcbahgfedcbahgfedcba", - app2.product_url().spec()); + EXPECT_FALSE(app2.is_removable()); + EXPECT_EQ("hgfedcbahgfedcbahgfedcbahgfedcba", app2.product_id()); ASSERT_EQ(3U, app2.primary_mimetypes().size()); EXPECT_EQ("image/jpeg", *app2.primary_mimetypes()[0]); @@ -110,6 +104,8 @@ TEST(DriveAPIParserTest, AppListParser) { EXPECT_EQ(DriveAppIcon::DOCUMENT, icon2.category()); EXPECT_EQ(10, icon2.icon_side_length()); EXPECT_EQ("http://www.example.com/d10.png", icon2.icon_url().spec()); + + EXPECT_EQ("https://www.example.com/createForApp2", app2.create_url().spec()); } // Test file list parsing. @@ -123,12 +119,6 @@ TEST(DriveAPIParserTest, FileListParser) { scoped_ptr<FileList> filelist(new FileList); EXPECT_TRUE(filelist->Parse(*document)); - EXPECT_EQ("\"WtRjAPZWbDA7_fkFjc5ojsEvDEF/zyHTfoHpnRHovyi8bWpwK0DXABC\"", - filelist->etag()); - EXPECT_EQ("EAIaggELEgA6egpi96It9mH_____f_8AAP__AAD_okhU-cHLz83KzszMxsjMzs_Ry" - "NGJnridyrbHs7u9tv8AAP__AP7__n__AP8AokhU-cHLz83KzszMxsjMzs_RyNGJnr" - "idyrbHs7u9tv8A__4QZCEiXPTi_wtIgTkAAAAAngnSXUgCDEAAIgsJPgart10AAAA" - "ABC", filelist->next_page_token()); EXPECT_EQ(GURL("https://www.googleapis.com/drive/v2/files?pageToken=EAIaggEL" "EgA6egpi96It9mH_____f_8AAP__AAD_okhU-cHLz83KzszMxsjMzs_RyNGJ" "nridyrbHs7u9tv8AAP__AP7__n__AP8AokhU-cHLz83KzszMxsjMzs_RyNGJ" @@ -144,11 +134,7 @@ TEST(DriveAPIParserTest, FileListParser) { EXPECT_EQ("My first file data", file1.title()); EXPECT_EQ("application/octet-stream", file1.mime_type()); - EXPECT_FALSE(file1.labels().is_starred()); - EXPECT_FALSE(file1.labels().is_hidden()); EXPECT_FALSE(file1.labels().is_trashed()); - EXPECT_FALSE(file1.labels().is_restricted()); - EXPECT_TRUE(file1.labels().is_viewed()); EXPECT_FALSE(file1.shared()); EXPECT_EQ(640, file1.image_media_metadata().width()); @@ -164,29 +150,19 @@ TEST(DriveAPIParserTest, FileListParser) { ASSERT_TRUE( util::GetTimeFromString("2012-07-27T05:43:20.269Z", &modified_time)); EXPECT_EQ(modified_time, file1.modified_date()); - EXPECT_EQ(modified_time, file1.modified_by_me_date()); ASSERT_EQ(1U, file1.parents().size()); - EXPECT_EQ("0B4v7G8yEYAWHYW1OcExsUVZLABC", file1.parents()[0]->file_id()); + EXPECT_EQ("0B4v7G8yEYAWHYW1OcExsUVZLABC", file1.parents()[0].file_id()); EXPECT_EQ(GURL("https://www.googleapis.com/drive/v2/files/" "0B4v7G8yEYAWHYW1OcExsUVZLABC"), - file1.parents()[0]->parent_link()); - EXPECT_FALSE(file1.parents()[0]->is_root()); + file1.parents()[0].parent_link()); - EXPECT_EQ(GURL("https://www.example.com/download"), file1.download_url()); - EXPECT_EQ("ext", file1.file_extension()); EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e", file1.md5_checksum()); EXPECT_EQ(1000U, file1.file_size()); - EXPECT_EQ(GURL("https://www.googleapis.com/drive/v2/files/" - "0B4v7G8yEYAWHUmRrU2lMS2hLABC"), - file1.self_link()); EXPECT_EQ(GURL("https://docs.google.com/file/d/" "0B4v7G8yEYAWHUmRrU2lMS2hLABC/edit"), file1.alternate_link()); - EXPECT_EQ(GURL("https://docs.google.com/uc?" - "id=0B4v7G8yEYAWHUmRrU2lMS2hLABC&export=download"), - file1.web_content_link()); ASSERT_EQ(1U, file1.open_with_links().size()); EXPECT_EQ("1234567890", file1.open_with_links()[0].app_id); EXPECT_EQ(GURL("http://open_with_link/url"), @@ -197,11 +173,7 @@ TEST(DriveAPIParserTest, FileListParser) { EXPECT_EQ("Test Google Document", file2.title()); EXPECT_EQ("application/vnd.google-apps.document", file2.mime_type()); - EXPECT_TRUE(file2.labels().is_starred()); - EXPECT_TRUE(file2.labels().is_hidden()); EXPECT_TRUE(file2.labels().is_trashed()); - EXPECT_TRUE(file2.labels().is_restricted()); - EXPECT_TRUE(file2.labels().is_viewed()); EXPECT_TRUE(file2.shared()); EXPECT_EQ(-1, file2.image_media_metadata().width()); @@ -217,13 +189,6 @@ TEST(DriveAPIParserTest, FileListParser) { ASSERT_EQ(0U, file2.parents().size()); - EXPECT_EQ(GURL("https://docs.google.com/a/chromium.org/document/d/" - "1Pc8jzfU1ErbN_eucMMqdqzY3eBm0v8sxXm_1CtLxABC/preview"), - file2.embed_link()); - EXPECT_EQ(GURL("https://docs.google.com/feeds/vt?gd=true&" - "id=1Pc8jzfU1ErbN_eucMMqdqzY3eBm0v8sxXm_1CtLxABC&" - "v=3&s=AMedNnoAAAAAUBJyB0g8HbxZaLRnlztxefZPS24LiXYZ&sz=s220"), - file2.thumbnail_link()); EXPECT_EQ(0U, file2.open_with_links().size()); // Check file 3 (a folder) @@ -235,8 +200,7 @@ TEST(DriveAPIParserTest, FileListParser) { EXPECT_FALSE(file3.shared()); ASSERT_EQ(1U, file3.parents().size()); - EXPECT_EQ("0AIv7G8yEYAWHUk9ABC", file3.parents()[0]->file_id()); - EXPECT_TRUE(file3.parents()[0]->is_root()); + EXPECT_EQ("0AIv7G8yEYAWHUk9ABC", file3.parents()[0].file_id()); EXPECT_EQ(0U, file3.open_with_links().size()); } @@ -251,9 +215,6 @@ TEST(DriveAPIParserTest, ChangeListParser) { scoped_ptr<ChangeList> changelist(new ChangeList); EXPECT_TRUE(changelist->Parse(*document)); - EXPECT_EQ("\"Lp2bjAtLP341hvGmYHhxjYyBPJ8/BWbu_eylt5f_aGtCN6mGRv9hABC\"", - changelist->etag()); - EXPECT_EQ("8929", changelist->next_page_token()); EXPECT_EQ("https://www.googleapis.com/drive/v2/changes?pageToken=8929", changelist->next_link().spec()); EXPECT_EQ(13664, changelist->largest_change_id()); @@ -266,6 +227,7 @@ TEST(DriveAPIParserTest, ChangeListParser) { EXPECT_EQ("1Pc8jzfU1ErbN_eucMMqdqzY3eBm0v8sxXm_1CtLxABC", change1.file_id()); EXPECT_EQ(change1.file_id(), change1.file()->file_id()); EXPECT_FALSE(change1.file()->shared()); + EXPECT_EQ(change1.file()->modified_date(), change1.modification_date()); const ChangeResource& change2 = *changelist->items()[1]; EXPECT_EQ(8424, change2.change_id()); @@ -273,6 +235,7 @@ TEST(DriveAPIParserTest, ChangeListParser) { EXPECT_EQ("0B4v7G8yEYAWHUmRrU2lMS2hLABC", change2.file_id()); EXPECT_EQ(change2.file_id(), change2.file()->file_id()); EXPECT_TRUE(change2.file()->shared()); + EXPECT_EQ(change2.file()->modified_date(), change2.modification_date()); const ChangeResource& change3 = *changelist->items()[2]; EXPECT_EQ(8429, change3.change_id()); @@ -280,12 +243,17 @@ TEST(DriveAPIParserTest, ChangeListParser) { EXPECT_EQ("0B4v7G8yEYAWHYW1OcExsUVZLABC", change3.file_id()); EXPECT_EQ(change3.file_id(), change3.file()->file_id()); EXPECT_FALSE(change3.file()->shared()); + EXPECT_EQ(change3.file()->modified_date(), change3.modification_date()); // Deleted entry. const ChangeResource& change4 = *changelist->items()[3]; EXPECT_EQ(8430, change4.change_id()); EXPECT_EQ("ABCv7G8yEYAWHc3Y5X0hMSkJYXYZ", change4.file_id()); EXPECT_TRUE(change4.is_deleted()); + base::Time modification_time; + ASSERT_TRUE(util::GetTimeFromString("2012-07-27T12:34:56.789Z", + &modification_time)); + EXPECT_EQ(modification_time, change4.modification_date()); } TEST(DriveAPIParserTest, HasKind) { diff --git a/chromium/google_apis/drive/drive_api_requests.cc b/chromium/google_apis/drive/drive_api_requests.cc index f0960e6f237..a63757112b8 100644 --- a/chromium/google_apis/drive/drive_api_requests.cc +++ b/chromium/google_apis/drive/drive_api_requests.cc @@ -113,6 +113,15 @@ void ParseFileResourceWithUploadRangeAndRun( callback.Run(response, file_resource.Pass()); } +// Creates a Parents value which can be used as a part of request body. +scoped_ptr<base::DictionaryValue> CreateParentValue( + const std::string& file_id) { + scoped_ptr<base::DictionaryValue> parent(new base::DictionaryValue); + parent->SetString("kind", kParentLinkKind); + parent->SetString("id", file_id); + return parent.Pass(); +} + } // namespace namespace drive { @@ -153,6 +162,29 @@ GURL FilesGetRequest::GetURLInternal() const { return url_generator_.GetFilesGetUrl(file_id_); } +//============================ FilesAuthorizeRequest =========================== + +FilesAuthorizeRequest::FilesAuthorizeRequest( + RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const FileResourceCallback& callback) + : DriveApiDataRequest( + sender, + base::Bind(&ParseJsonAndRun<FileResource>, callback)), + url_generator_(url_generator) { + DCHECK(!callback.is_null()); +} + +FilesAuthorizeRequest::~FilesAuthorizeRequest() {} + +net::URLFetcher::RequestType FilesAuthorizeRequest::GetRequestType() const { + return net::URLFetcher::POST; +} + +GURL FilesAuthorizeRequest::GetURLInternal() const { + return url_generator_.GetFilesAuthorizeUrl(file_id_, app_id_); +} + //============================ FilesInsertRequest ============================ FilesInsertRequest::FilesInsertRequest( @@ -178,9 +210,17 @@ bool FilesInsertRequest::GetContentData(std::string* upload_content_type, base::DictionaryValue root; + if (!last_viewed_by_me_date_.is_null()) { + root.SetString("lastViewedByMeDate", + util::FormatTimeAsString(last_viewed_by_me_date_)); + } + if (!mime_type_.empty()) root.SetString("mimeType", mime_type_); + if (!modified_date_.is_null()) + root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_)); + if (!parents_.empty()) { base::ListValue* parents_value = new base::ListValue; for (size_t i = 0; i < parents_.size(); ++i) { @@ -491,18 +531,40 @@ GURL ChangesListNextPageRequest::GetURLInternal() const { AppsListRequest::AppsListRequest( RequestSender* sender, const DriveApiUrlGenerator& url_generator, + bool use_internal_endpoint, const AppListCallback& callback) : DriveApiDataRequest( sender, base::Bind(&ParseJsonAndRun<AppList>, callback)), - url_generator_(url_generator) { + url_generator_(url_generator), + use_internal_endpoint_(use_internal_endpoint) { DCHECK(!callback.is_null()); } AppsListRequest::~AppsListRequest() {} GURL AppsListRequest::GetURLInternal() const { - return url_generator_.GetAppsListUrl(); + return url_generator_.GetAppsListUrl(use_internal_endpoint_); +} + +//============================== AppsDeleteRequest =========================== + +AppsDeleteRequest::AppsDeleteRequest(RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const EntryActionCallback& callback) + : EntryActionRequest(sender, callback), + url_generator_(url_generator) { + DCHECK(!callback.is_null()); +} + +AppsDeleteRequest::~AppsDeleteRequest() {} + +net::URLFetcher::RequestType AppsDeleteRequest::GetRequestType() const { + return net::URLFetcher::DELETE_REQUEST; +} + +GURL AppsDeleteRequest::GetURL() const { + return url_generator_.GetAppsDeleteUrl(app_id_); } //========================== ChildrenInsertRequest ============================ @@ -582,7 +644,7 @@ InitiateUploadNewFileRequest::InitiateUploadNewFileRequest( InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {} GURL InitiateUploadNewFileRequest::GetURL() const { - return url_generator_.GetInitiateUploadNewFileUrl(); + return url_generator_.GetInitiateUploadNewFileUrl(!modified_date_.is_null()); } net::URLFetcher::RequestType @@ -599,15 +661,16 @@ bool InitiateUploadNewFileRequest::GetContentData( root.SetString("title", title_); // Fill parent link. - { - scoped_ptr<base::DictionaryValue> parent(new base::DictionaryValue); - parent->SetString("kind", kParentLinkKind); - parent->SetString("id", parent_resource_id_); + scoped_ptr<base::ListValue> parents(new base::ListValue); + parents->Append(CreateParentValue(parent_resource_id_).release()); + root.Set("parents", parents.release()); - scoped_ptr<base::ListValue> parents(new base::ListValue); - parents->Append(parent.release()); + if (!modified_date_.is_null()) + root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_)); - root.Set("parents", parents.release()); + if (!last_viewed_by_me_date_.is_null()) { + root.SetString("lastViewedByMeDate", + util::FormatTimeAsString(last_viewed_by_me_date_)); } base::JSONWriter::Write(&root, upload_content); @@ -639,7 +702,8 @@ InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest( InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {} GURL InitiateUploadExistingFileRequest::GetURL() const { - return url_generator_.GetInitiateUploadExistingFileUrl(resource_id_); + return url_generator_.GetInitiateUploadExistingFileUrl( + resource_id_, !modified_date_.is_null()); } net::URLFetcher::RequestType @@ -655,6 +719,37 @@ InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const { return headers; } +bool InitiateUploadExistingFileRequest::GetContentData( + std::string* upload_content_type, + std::string* upload_content) { + base::DictionaryValue root; + if (!parent_resource_id_.empty()) { + scoped_ptr<base::ListValue> parents(new base::ListValue); + parents->Append(CreateParentValue(parent_resource_id_).release()); + root.Set("parents", parents.release()); + } + + if (!title_.empty()) + root.SetString("title", title_); + + if (!modified_date_.is_null()) + root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_)); + + if (!last_viewed_by_me_date_.is_null()) { + root.SetString("lastViewedByMeDate", + util::FormatTimeAsString(last_viewed_by_me_date_)); + } + + if (root.empty()) + return false; + + *upload_content_type = kContentTypeApplicationJson; + base::JSONWriter::Write(&root, upload_content); + DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type + << ", [" << *upload_content << "]"; + return true; +} + //============================ ResumeUploadRequest =========================== ResumeUploadRequest::ResumeUploadRequest( @@ -739,5 +834,72 @@ DownloadFileRequest::DownloadFileRequest( DownloadFileRequest::~DownloadFileRequest() { } +//========================== PermissionsInsertRequest ========================== + +PermissionsInsertRequest::PermissionsInsertRequest( + RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const EntryActionCallback& callback) + : EntryActionRequest(sender, callback), + url_generator_(url_generator), + type_(PERMISSION_TYPE_USER), + role_(PERMISSION_ROLE_READER) { +} + +PermissionsInsertRequest::~PermissionsInsertRequest() { +} + +GURL PermissionsInsertRequest::GetURL() const { + return url_generator_.GetPermissionsInsertUrl(id_); +} + +net::URLFetcher::RequestType +PermissionsInsertRequest::GetRequestType() const { + return net::URLFetcher::POST; +} + +bool PermissionsInsertRequest::GetContentData(std::string* upload_content_type, + std::string* upload_content) { + *upload_content_type = kContentTypeApplicationJson; + + base::DictionaryValue root; + switch (type_) { + case PERMISSION_TYPE_ANYONE: + root.SetString("type", "anyone"); + break; + case PERMISSION_TYPE_DOMAIN: + root.SetString("type", "domain"); + break; + case PERMISSION_TYPE_GROUP: + root.SetString("type", "group"); + break; + case PERMISSION_TYPE_USER: + root.SetString("type", "user"); + break; + } + switch (role_) { + case PERMISSION_ROLE_OWNER: + root.SetString("role", "owner"); + break; + case PERMISSION_ROLE_READER: + root.SetString("role", "reader"); + break; + case PERMISSION_ROLE_WRITER: + root.SetString("role", "writer"); + break; + case PERMISSION_ROLE_COMMENTER: + root.SetString("role", "reader"); + { + base::ListValue* list = new base::ListValue; + list->AppendString("commenter"); + root.Set("additionalRoles", list); + } + break; + } + root.SetString("value", value_); + base::JSONWriter::Write(&root, upload_content); + return true; +} + } // namespace drive } // namespace google_apis diff --git a/chromium/google_apis/drive/drive_api_requests.h b/chromium/google_apis/drive/drive_api_requests.h index 6f10aa66d95..59bffd67b87 100644 --- a/chromium/google_apis/drive/drive_api_requests.h +++ b/chromium/google_apis/drive/drive_api_requests.h @@ -93,6 +93,38 @@ class FilesGetRequest : public DriveApiDataRequest { DISALLOW_COPY_AND_ASSIGN(FilesGetRequest); }; +//============================ FilesAuthorizeRequest =========================== + +// This class performs request for authorizing an app to access a file. +// This request is mapped to /drive/v2internal/file/authorize internal endpoint. +class FilesAuthorizeRequest : public DriveApiDataRequest { + public: + FilesAuthorizeRequest(RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const FileResourceCallback& callback); + virtual ~FilesAuthorizeRequest(); + + // Required parameter. + const std::string& file_id() const { return file_id_; } + void set_file_id(const std::string& file_id) { file_id_ = file_id; } + const std::string& app_id() const { return app_id_; } + void set_app_id(const std::string& app_id) { app_id_ = app_id; } + + protected: + // Overridden from GetDataRequest. + virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; + + // Overridden from DriveApiDataRequest. + virtual GURL GetURLInternal() const OVERRIDE; + + private: + const DriveApiUrlGenerator url_generator_; + std::string file_id_; + std::string app_id_; + + DISALLOW_COPY_AND_ASSIGN(FilesAuthorizeRequest); +}; + //============================ FilesInsertRequest ============================= // This class performs the request for creating a resource. @@ -108,11 +140,23 @@ class FilesInsertRequest : public DriveApiDataRequest { virtual ~FilesInsertRequest(); // Optional request body. + const base::Time& last_viewed_by_me_date() const { + return last_viewed_by_me_date_; + } + void set_last_viewed_by_me_date(const base::Time& last_viewed_by_me_date) { + last_viewed_by_me_date_ = last_viewed_by_me_date; + } + const std::string& mime_type() const { return mime_type_; } void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; } + const base::Time& modified_date() const { return modified_date_; } + void set_modified_date(const base::Time& modified_date) { + modified_date_ = modified_date; + } + const std::vector<std::string>& parents() const { return parents_; } void add_parent(const std::string& parent) { parents_.push_back(parent); } @@ -131,7 +175,9 @@ class FilesInsertRequest : public DriveApiDataRequest { private: const DriveApiUrlGenerator url_generator_; + base::Time last_viewed_by_me_date_; std::string mime_type_; + base::Time modified_date_; std::vector<std::string> parents_; std::string title_; @@ -491,6 +537,7 @@ class AppsListRequest : public DriveApiDataRequest { public: AppsListRequest(RequestSender* sender, const DriveApiUrlGenerator& url_generator, + bool use_internal_endpoint, const AppListCallback& callback); virtual ~AppsListRequest(); @@ -500,10 +547,39 @@ class AppsListRequest : public DriveApiDataRequest { private: const DriveApiUrlGenerator url_generator_; + bool use_internal_endpoint_; DISALLOW_COPY_AND_ASSIGN(AppsListRequest); }; +//============================= AppsDeleteRequest ============================== + +// This class performs the request for deleting a Drive app. +// This request is mapped to +// https://developers.google.com/drive/v2/reference/files/trash +class AppsDeleteRequest : public EntryActionRequest { + public: + AppsDeleteRequest(RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const EntryActionCallback& callback); + virtual ~AppsDeleteRequest(); + + // Required parameter. + const std::string& app_id() const { return app_id_; } + void set_app_id(const std::string& app_id) { app_id_ = app_id; } + + protected: + // Overridden from UrlFetchRequestBase. + virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; + virtual GURL GetURL() const OVERRIDE; + + private: + const DriveApiUrlGenerator url_generator_; + std::string app_id_; + + DISALLOW_COPY_AND_ASSIGN(AppsDeleteRequest); +}; + //========================== ChildrenInsertRequest ============================ // This class performs the request for inserting a resource to a directory. @@ -596,6 +672,18 @@ class InitiateUploadNewFileRequest : public InitiateUploadRequestBase { const InitiateUploadCallback& callback); virtual ~InitiateUploadNewFileRequest(); + // Optional parameters. + const base::Time& modified_date() const { return modified_date_; } + void set_modified_date(const base::Time& modified_date) { + modified_date_ = modified_date; + } + const base::Time& last_viewed_by_me_date() const { + return last_viewed_by_me_date_; + } + void set_last_viewed_by_me_date(const base::Time& last_viewed_by_me_date) { + last_viewed_by_me_date_ = last_viewed_by_me_date; + } + protected: // UrlFetchRequestBase overrides. virtual GURL GetURL() const OVERRIDE; @@ -608,6 +696,9 @@ class InitiateUploadNewFileRequest : public InitiateUploadRequestBase { const std::string parent_resource_id_; const std::string title_; + base::Time modified_date_; + base::Time last_viewed_by_me_date_; + DISALLOW_COPY_AND_ASSIGN(InitiateUploadNewFileRequest); }; @@ -631,17 +722,43 @@ class InitiateUploadExistingFileRequest : public InitiateUploadRequestBase { const InitiateUploadCallback& callback); virtual ~InitiateUploadExistingFileRequest(); + + // Optional parameters. + const std::string& parent_resource_id() const { return parent_resource_id_; } + void set_parent_resource_id(const std::string& parent_resource_id) { + parent_resource_id_ = parent_resource_id; + } + const std::string& title() const { return title_; } + void set_title(const std::string& title) { title_ = title; } + const base::Time& modified_date() const { return modified_date_; } + void set_modified_date(const base::Time& modified_date) { + modified_date_ = modified_date; + } + const base::Time& last_viewed_by_me_date() const { + return last_viewed_by_me_date_; + } + void set_last_viewed_by_me_date(const base::Time& last_viewed_by_me_date) { + last_viewed_by_me_date_ = last_viewed_by_me_date; + } + protected: // UrlFetchRequestBase overrides. virtual GURL GetURL() const OVERRIDE; virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; + virtual bool GetContentData(std::string* upload_content_type, + std::string* upload_content) OVERRIDE; private: const DriveApiUrlGenerator url_generator_; const std::string resource_id_; const std::string etag_; + std::string parent_resource_id_; + std::string title_; + base::Time modified_date_; + base::Time last_viewed_by_me_date_; + DISALLOW_COPY_AND_ASSIGN(InitiateUploadExistingFileRequest); }; @@ -727,6 +844,54 @@ class DownloadFileRequest : public DownloadFileRequestBase { DISALLOW_COPY_AND_ASSIGN(DownloadFileRequest); }; +//========================== PermissionsInsertRequest ========================== + +// Enumeration type for specifying type of permissions. +enum PermissionType { + PERMISSION_TYPE_ANYONE, + PERMISSION_TYPE_DOMAIN, + PERMISSION_TYPE_GROUP, + PERMISSION_TYPE_USER, +}; + +// Enumeration type for specifying the role of permissions. +enum PermissionRole { + PERMISSION_ROLE_OWNER, + PERMISSION_ROLE_READER, + PERMISSION_ROLE_WRITER, + PERMISSION_ROLE_COMMENTER, +}; + +// This class performs the request for adding permission on a specified file. +class PermissionsInsertRequest : public EntryActionRequest { + public: + // See https://developers.google.com/drive/v2/reference/permissions/insert. + PermissionsInsertRequest(RequestSender* sender, + const DriveApiUrlGenerator& url_generator, + const EntryActionCallback& callback); + virtual ~PermissionsInsertRequest(); + + void set_id(const std::string& id) { id_ = id; } + void set_type(PermissionType type) { type_ = type; } + void set_role(PermissionRole role) { role_ = role; } + void set_value(const std::string& value) { value_ = value; } + + // UrlFetchRequestBase overrides. + virtual GURL GetURL() const OVERRIDE; + virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; + virtual bool GetContentData(std::string* upload_content_type, + std::string* upload_content) OVERRIDE; + + private: + const DriveApiUrlGenerator url_generator_; + std::string id_; + PermissionType type_; + PermissionRole role_; + std::string value_; + + DISALLOW_COPY_AND_ASSIGN(PermissionsInsertRequest); +}; + } // namespace drive } // namespace google_apis diff --git a/chromium/google_apis/drive/drive_api_requests_unittest.cc b/chromium/google_apis/drive/drive_api_requests_unittest.cc index 466240cd369..9281b866a88 100644 --- a/chromium/google_apis/drive/drive_api_requests_unittest.cc +++ b/chromium/google_apis/drive/drive_api_requests_unittest.cc @@ -6,6 +6,7 @@ #include "base/file_util.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "base/json/json_reader.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" @@ -37,6 +38,13 @@ const char kTestChildrenResponse[] = "\"childLink\": \"child_link\",\n" "}\n"; +const char kTestPermissionResponse[] = + "{\n" + "\"kind\": \"drive#permission\",\n" + "\"id\": \"resource_id\",\n" + "\"selfLink\": \"self_link\",\n" + "}\n"; + const char kTestUploadExistingFilePath[] = "/upload/existingfile/path"; const char kTestUploadNewFilePath[] = "/upload/newfile/path"; const char kTestDownloadPathPrefix[] = "/download/"; @@ -418,6 +426,10 @@ TEST_F(DriveApiRequestsTest, DriveApiDataRequest_Fields) { } TEST_F(DriveApiRequestsTest, FilesInsertRequest) { + const base::Time::Exploded kModifiedDate = {2012, 7, 0, 19, 15, 59, 13, 123}; + const base::Time::Exploded kLastViewedByMeDate = + {2013, 7, 0, 19, 15, 59, 13, 123}; + // Set an expected data file containing the directory's entry data. expected_data_file_path_ = test_util::GetTestFilePath("drive/directory_entry.json"); @@ -434,7 +446,10 @@ TEST_F(DriveApiRequestsTest, FilesInsertRequest) { test_util::CreateQuitCallback( &run_loop, test_util::CreateCopyResultCallback(&error, &file_resource))); + request->set_last_viewed_by_me_date( + base::Time::FromUTCExploded(kLastViewedByMeDate)); request->set_mime_type("application/vnd.google-apps.folder"); + request->set_modified_date(base::Time::FromUTCExploded(kModifiedDate)); request->add_parent("root"); request->set_title("new directory"); request_sender_->StartRequestWithRetry(request); @@ -447,6 +462,12 @@ TEST_F(DriveApiRequestsTest, FilesInsertRequest) { EXPECT_EQ("application/json", http_request_.headers["Content-Type"]); EXPECT_TRUE(http_request_.has_content); + EXPECT_EQ("{\"lastViewedByMeDate\":\"2013-07-19T15:59:13.123Z\"," + "\"mimeType\":\"application/vnd.google-apps.folder\"," + "\"modifiedDate\":\"2012-07-19T15:59:13.123Z\"," + "\"parents\":[{\"id\":\"root\"}]," + "\"title\":\"new directory\"}", + http_request_.content); scoped_ptr<FileResource> expected( FileResource::CreateFrom( @@ -585,6 +606,7 @@ TEST_F(DriveApiRequestsTest, AppsListRequest) { drive::AppsListRequest* request = new drive::AppsListRequest( request_sender_.get(), *url_generator_, + false, // use_internal_endpoint test_util::CreateQuitCallback( &run_loop, test_util::CreateCopyResultCallback(&error, &app_list))); @@ -1257,6 +1279,60 @@ TEST_F(DriveApiRequestsTest, UploadNewLargeFileRequest) { } } +TEST_F(DriveApiRequestsTest, UploadNewFileWithMetadataRequest) { + const base::Time::Exploded kModifiedDate = {2012, 7, 0, 19, 15, 59, 13, 123}; + const base::Time::Exploded kLastViewedByMeDate = + {2013, 7, 0, 19, 15, 59, 13, 123}; + + // Set an expected url for uploading. + expected_upload_path_ = kTestUploadNewFilePath; + + const char kTestContentType[] = "text/plain"; + const std::string kTestContent(100, 'a'); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_url; + + // Initiate uploading a new file to the directory with "parent_resource_id". + { + base::RunLoop run_loop; + drive::InitiateUploadNewFileRequest* request = + new drive::InitiateUploadNewFileRequest( + request_sender_.get(), + *url_generator_, + kTestContentType, + kTestContent.size(), + "parent_resource_id", // The resource id of the parent directory. + "new file title", // The title of the file being uploaded. + test_util::CreateQuitCallback( + &run_loop, + test_util::CreateCopyResultCallback(&error, &upload_url))); + request->set_modified_date(base::Time::FromUTCExploded(kModifiedDate)); + request->set_last_viewed_by_me_date( + base::Time::FromUTCExploded(kLastViewedByMeDate)); + request_sender_->StartRequestWithRetry(request); + run_loop.Run(); + } + + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_EQ(kTestUploadNewFilePath, upload_url.path()); + EXPECT_EQ(kTestContentType, http_request_.headers["X-Upload-Content-Type"]); + EXPECT_EQ(base::Int64ToString(kTestContent.size()), + http_request_.headers["X-Upload-Content-Length"]); + + EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); + EXPECT_EQ("/upload/drive/v2/files?uploadType=resumable&setModifiedDate=true", + http_request_.relative_url); + EXPECT_EQ("application/json", http_request_.headers["Content-Type"]); + EXPECT_TRUE(http_request_.has_content); + EXPECT_EQ("{\"lastViewedByMeDate\":\"2013-07-19T15:59:13.123Z\"," + "\"modifiedDate\":\"2012-07-19T15:59:13.123Z\"," + "\"parents\":[{\"id\":\"parent_resource_id\"," + "\"kind\":\"drive#fileLink\"}]," + "\"title\":\"new file title\"}", + http_request_.content); +} + TEST_F(DriveApiRequestsTest, UploadExistingFileRequest) { // Set an expected url for uploading. expected_upload_path_ = kTestUploadExistingFilePath; @@ -1573,6 +1649,65 @@ TEST_F(DriveApiRequestsTest, EXPECT_FALSE(new_entry.get()); } +TEST_F(DriveApiRequestsTest, UploadExistingFileWithMetadataRequest) { + const base::Time::Exploded kModifiedDate = {2012, 7, 0, 19, 15, 59, 13, 123}; + const base::Time::Exploded kLastViewedByMeDate = + {2013, 7, 0, 19, 15, 59, 13, 123}; + + // Set an expected url for uploading. + expected_upload_path_ = kTestUploadExistingFilePath; + + const char kTestContentType[] = "text/plain"; + const std::string kTestContent(100, 'a'); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_url; + + // Initiate uploading a new file to the directory with "parent_resource_id". + { + base::RunLoop run_loop; + drive::InitiateUploadExistingFileRequest* request = + new drive::InitiateUploadExistingFileRequest( + request_sender_.get(), + *url_generator_, + kTestContentType, + kTestContent.size(), + "resource_id", // The resource id of the file to be overwritten. + kTestETag, + test_util::CreateQuitCallback( + &run_loop, + test_util::CreateCopyResultCallback(&error, &upload_url))); + request->set_parent_resource_id("new_parent_resource_id"); + request->set_title("new file title"); + request->set_modified_date(base::Time::FromUTCExploded(kModifiedDate)); + request->set_last_viewed_by_me_date( + base::Time::FromUTCExploded(kLastViewedByMeDate)); + + request_sender_->StartRequestWithRetry(request); + run_loop.Run(); + } + + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_EQ(kTestUploadExistingFilePath, upload_url.path()); + EXPECT_EQ(kTestContentType, http_request_.headers["X-Upload-Content-Type"]); + EXPECT_EQ(base::Int64ToString(kTestContent.size()), + http_request_.headers["X-Upload-Content-Length"]); + EXPECT_EQ(kTestETag, http_request_.headers["If-Match"]); + + EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); + EXPECT_EQ("/upload/drive/v2/files/resource_id?" + "uploadType=resumable&setModifiedDate=true", + http_request_.relative_url); + EXPECT_EQ("application/json", http_request_.headers["Content-Type"]); + EXPECT_TRUE(http_request_.has_content); + EXPECT_EQ("{\"lastViewedByMeDate\":\"2013-07-19T15:59:13.123Z\"," + "\"modifiedDate\":\"2012-07-19T15:59:13.123Z\"," + "\"parents\":[{\"id\":\"new_parent_resource_id\"," + "\"kind\":\"drive#fileLink\"}]," + "\"title\":\"new file title\"}", + http_request_.content); +} + TEST_F(DriveApiRequestsTest, DownloadFileRequest) { const base::FilePath kDownloadedFilePath = temp_dir_.path().AppendASCII("cache_file"); @@ -1644,4 +1779,77 @@ TEST_F(DriveApiRequestsTest, DownloadFileRequest_GetContentCallback) { EXPECT_EQ(expected_contents, contents); } +TEST_F(DriveApiRequestsTest, PermissionsInsertRequest) { + expected_content_type_ = "application/json"; + expected_content_ = kTestPermissionResponse; + + GDataErrorCode error = GDATA_OTHER_ERROR; + + // Add comment permission to the user "user@example.com". + { + base::RunLoop run_loop; + drive::PermissionsInsertRequest* request = + new drive::PermissionsInsertRequest( + request_sender_.get(), + *url_generator_, + test_util::CreateQuitCallback( + &run_loop, + test_util::CreateCopyResultCallback(&error))); + request->set_id("resource_id"); + request->set_role(drive::PERMISSION_ROLE_COMMENTER); + request->set_type(drive::PERMISSION_TYPE_USER); + request->set_value("user@example.com"); + request_sender_->StartRequestWithRetry(request); + run_loop.Run(); + } + + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); + EXPECT_EQ("/drive/v2/files/resource_id/permissions", + http_request_.relative_url); + EXPECT_EQ("application/json", http_request_.headers["Content-Type"]); + + scoped_ptr<base::Value> expected(base::JSONReader::Read( + "{\"additionalRoles\":[\"commenter\"], \"role\":\"reader\", " + "\"type\":\"user\",\"value\":\"user@example.com\"}")); + ASSERT_TRUE(expected); + + scoped_ptr<base::Value> result(base::JSONReader::Read(http_request_.content)); + EXPECT_TRUE(http_request_.has_content); + EXPECT_TRUE(base::Value::Equals(expected.get(), result.get())); + + // Add "can edit" permission to users in "example.com". + error = GDATA_OTHER_ERROR; + { + base::RunLoop run_loop; + drive::PermissionsInsertRequest* request = + new drive::PermissionsInsertRequest( + request_sender_.get(), + *url_generator_, + test_util::CreateQuitCallback( + &run_loop, + test_util::CreateCopyResultCallback(&error))); + request->set_id("resource_id2"); + request->set_role(drive::PERMISSION_ROLE_WRITER); + request->set_type(drive::PERMISSION_TYPE_DOMAIN); + request->set_value("example.com"); + request_sender_->StartRequestWithRetry(request); + run_loop.Run(); + } + + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); + EXPECT_EQ("/drive/v2/files/resource_id2/permissions", + http_request_.relative_url); + EXPECT_EQ("application/json", http_request_.headers["Content-Type"]); + + expected.reset(base::JSONReader::Read( + "{\"role\":\"writer\", \"type\":\"domain\",\"value\":\"example.com\"}")); + ASSERT_TRUE(expected); + + result.reset(base::JSONReader::Read(http_request_.content)); + EXPECT_TRUE(http_request_.has_content); + EXPECT_TRUE(base::Value::Equals(expected.get(), result.get())); +} + } // namespace google_apis diff --git a/chromium/google_apis/drive/drive_api_url_generator.cc b/chromium/google_apis/drive/drive_api_url_generator.cc index c12b947d3dc..b8374e27699 100644 --- a/chromium/google_apis/drive/drive_api_url_generator.cc +++ b/chromium/google_apis/drive/drive_api_url_generator.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "google_apis/google_api_keys.h" #include "net/base/escape.h" #include "net/base/url_util.h" @@ -29,6 +30,14 @@ const char kDriveV2FileTrashUrlFormat[] = "/drive/v2/files/%s/trash"; const char kDriveV2InitiateUploadNewFileUrl[] = "/upload/drive/v2/files"; const char kDriveV2InitiateUploadExistingFileUrlPrefix[] = "/upload/drive/v2/files/"; +const char kDriveV2PermissionsUrlFormat[] = "/drive/v2/files/%s/permissions"; + +// apps.delete and file.authorize API is exposed through a special endpoint +// v2internal that is accessible only by the official API key for Chrome. +const char kDriveV2InternalAppsUrl[] = "/drive/v2internal/apps"; +const char kDriveV2AppsDeleteUrlFormat[] = "/drive/v2internal/apps/%s"; +const char kDriveV2FilesAuthorizeUrlFormat[] = + "/drive/v2internal/files/%s/authorize?appId=%s"; GURL AddResumableUploadParam(const GURL& url) { return net::AppendOrReplaceQueryParameter(url, "uploadType", "resumable"); @@ -56,14 +65,28 @@ GURL DriveApiUrlGenerator::GetAboutGetUrl() const { return base_url_.Resolve(kDriveV2AboutUrl); } -GURL DriveApiUrlGenerator::GetAppsListUrl() const { - return base_url_.Resolve(kDriveV2AppsUrl); +GURL DriveApiUrlGenerator::GetAppsListUrl(bool use_internal_endpoint) const { + return base_url_.Resolve(use_internal_endpoint ? + kDriveV2InternalAppsUrl : kDriveV2AppsUrl); +} + +GURL DriveApiUrlGenerator::GetAppsDeleteUrl(const std::string& app_id) const { + return base_url_.Resolve(base::StringPrintf( + kDriveV2AppsDeleteUrlFormat, net::EscapePath(app_id).c_str())); } GURL DriveApiUrlGenerator::GetFilesGetUrl(const std::string& file_id) const { return base_url_.Resolve(kDriveV2FileUrlPrefix + net::EscapePath(file_id)); } +GURL DriveApiUrlGenerator::GetFilesAuthorizeUrl( + const std::string& file_id, + const std::string& app_id) const { + return base_url_.Resolve(base::StringPrintf(kDriveV2FilesAuthorizeUrlFormat, + net::EscapePath(file_id).c_str(), + net::EscapePath(app_id).c_str())); +} + GURL DriveApiUrlGenerator::GetFilesInsertUrl() const { return base_url_.Resolve(kDriveV2FilesUrl); } @@ -162,17 +185,31 @@ GURL DriveApiUrlGenerator::GetChildrenDeleteUrl( net::EscapePath(child_id).c_str())); } -GURL DriveApiUrlGenerator::GetInitiateUploadNewFileUrl() const { - return AddResumableUploadParam( +GURL DriveApiUrlGenerator::GetInitiateUploadNewFileUrl( + bool set_modified_date) const { + GURL url = AddResumableUploadParam( base_url_.Resolve(kDriveV2InitiateUploadNewFileUrl)); + + // setModifiedDate is "false" by default. + if (set_modified_date) + url = net::AppendOrReplaceQueryParameter(url, "setModifiedDate", "true"); + + return url; } GURL DriveApiUrlGenerator::GetInitiateUploadExistingFileUrl( - const std::string& resource_id) const { - const GURL& url = base_url_.Resolve( + const std::string& resource_id, + bool set_modified_date) const { + GURL url = base_url_.Resolve( kDriveV2InitiateUploadExistingFileUrlPrefix + net::EscapePath(resource_id)); - return AddResumableUploadParam(url); + url = AddResumableUploadParam(url); + + // setModifiedDate is "false" by default. + if (set_modified_date) + url = net::AppendOrReplaceQueryParameter(url, "setModifiedDate", "true"); + + return url; } GURL DriveApiUrlGenerator::GenerateDownloadFileUrl( @@ -180,4 +217,11 @@ GURL DriveApiUrlGenerator::GenerateDownloadFileUrl( return base_download_url_.Resolve(net::EscapePath(resource_id)); } +GURL DriveApiUrlGenerator::GetPermissionsInsertUrl( + const std::string& resource_id) const { + return base_url_.Resolve( + base::StringPrintf(kDriveV2PermissionsUrlFormat, + net::EscapePath(resource_id).c_str())); +} + } // namespace google_apis diff --git a/chromium/google_apis/drive/drive_api_url_generator.h b/chromium/google_apis/drive/drive_api_url_generator.h index cf93edd3255..8c4b160a79f 100644 --- a/chromium/google_apis/drive/drive_api_url_generator.h +++ b/chromium/google_apis/drive/drive_api_url_generator.h @@ -30,11 +30,20 @@ class DriveApiUrlGenerator { GURL GetAboutGetUrl() const; // Returns a URL to invoke "Apps: list" method. - GURL GetAppsListUrl() const; + // Set |use_internal_endpoint| to true if official Chrome's API key is used + // and retrieving more information (related to App uninstall) is necessary. + GURL GetAppsListUrl(bool use_internal_endpoint) const; + + // Returns a URL to uninstall an app with the give |app_id|. + GURL GetAppsDeleteUrl(const std::string& app_id) const; // Returns a URL to fetch a file metadata. GURL GetFilesGetUrl(const std::string& file_id) const; + // Returns a URL to authorize an app to access a file. + GURL GetFilesAuthorizeUrl(const std::string& file_id, + const std::string& app_id) const; + // Returns a URL to create a resource. GURL GetFilesInsertUrl() const; @@ -72,15 +81,19 @@ class DriveApiUrlGenerator { const std::string& folder_id) const; // Returns a URL to initiate uploading a new file. - GURL GetInitiateUploadNewFileUrl() const; + GURL GetInitiateUploadNewFileUrl(bool set_modified_date) const; // Returns a URL to initiate uploading an existing file specified by // |resource_id|. - GURL GetInitiateUploadExistingFileUrl(const std::string& resource_id) const; + GURL GetInitiateUploadExistingFileUrl(const std::string& resource_id, + bool set_modified_date) const; // Generates a URL for downloading a file. GURL GenerateDownloadFileUrl(const std::string& resource_id) const; + // Generates a URL for adding permissions. + GURL GetPermissionsInsertUrl(const std::string& resource_id) const; + private: const GURL base_url_; const GURL base_download_url_; diff --git a/chromium/google_apis/drive/drive_api_url_generator_unittest.cc b/chromium/google_apis/drive/drive_api_url_generator_unittest.cc index 343b2791c4e..557a0af3f82 100644 --- a/chromium/google_apis/drive/drive_api_url_generator_unittest.cc +++ b/chromium/google_apis/drive/drive_api_url_generator_unittest.cc @@ -35,10 +35,20 @@ TEST_F(DriveApiUrlGeneratorTest, GetAboutGetUrl) { } TEST_F(DriveApiUrlGeneratorTest, GetAppsListUrl) { + const bool use_internal_url = true; + EXPECT_EQ("https://www.googleapis.com/drive/v2internal/apps", + url_generator_.GetAppsListUrl(use_internal_url).spec()); EXPECT_EQ("https://www.googleapis.com/drive/v2/apps", - url_generator_.GetAppsListUrl().spec()); + url_generator_.GetAppsListUrl(!use_internal_url).spec()); EXPECT_EQ("http://127.0.0.1:12345/drive/v2/apps", - test_url_generator_.GetAppsListUrl().spec()); + test_url_generator_.GetAppsListUrl(!use_internal_url).spec()); +} + +TEST_F(DriveApiUrlGeneratorTest, GetAppsDeleteUrl) { + EXPECT_EQ("https://www.googleapis.com/drive/v2internal/apps/0ADK06pfg", + url_generator_.GetAppsDeleteUrl("0ADK06pfg").spec()); + EXPECT_EQ("http://127.0.0.1:12345/drive/v2internal/apps/0ADK06pfg", + test_url_generator_.GetAppsDeleteUrl("0ADK06pfg").spec()); } TEST_F(DriveApiUrlGeneratorTest, GetFilesGetUrl) { @@ -58,6 +68,15 @@ TEST_F(DriveApiUrlGeneratorTest, GetFilesGetUrl) { test_url_generator_.GetFilesGetUrl("file:file_id").spec()); } +TEST_F(DriveApiUrlGeneratorTest, GetFilesAuthorizeUrl) { + EXPECT_EQ( + "https://www.googleapis.com/drive/v2internal/files/aa/authorize?appId=bb", + url_generator_.GetFilesAuthorizeUrl("aa", "bb").spec()); + EXPECT_EQ( + "http://127.0.0.1:12345/drive/v2internal/files/foo/authorize?appId=bar", + test_url_generator_.GetFilesAuthorizeUrl("foo", "bar").spec()); +} + TEST_F(DriveApiUrlGeneratorTest, GetFilesInsertUrl) { EXPECT_EQ("https://www.googleapis.com/drive/v2/files", url_generator_.GetFilesInsertUrl().spec()); @@ -338,45 +357,69 @@ TEST_F(DriveApiUrlGeneratorTest, GetChildrenDeleteUrl) { } TEST_F(DriveApiUrlGeneratorTest, GetInitiateUploadNewFileUrl) { + const bool kSetModifiedDate = true; + EXPECT_EQ( "https://www.googleapis.com/upload/drive/v2/files?uploadType=resumable", - url_generator_.GetInitiateUploadNewFileUrl().spec()); + url_generator_.GetInitiateUploadNewFileUrl(!kSetModifiedDate).spec()); EXPECT_EQ( "http://127.0.0.1:12345/upload/drive/v2/files?uploadType=resumable", - test_url_generator_.GetInitiateUploadNewFileUrl().spec()); + test_url_generator_.GetInitiateUploadNewFileUrl( + !kSetModifiedDate).spec()); + + EXPECT_EQ( + "http://127.0.0.1:12345/upload/drive/v2/files?uploadType=resumable&" + "setModifiedDate=true", + test_url_generator_.GetInitiateUploadNewFileUrl( + kSetModifiedDate).spec()); } TEST_F(DriveApiUrlGeneratorTest, GetInitiateUploadExistingFileUrl) { + const bool kSetModifiedDate = true; + // |resource_id| should be embedded into the url. EXPECT_EQ( "https://www.googleapis.com/upload/drive/v2/files/0ADK06pfg" "?uploadType=resumable", - url_generator_.GetInitiateUploadExistingFileUrl("0ADK06pfg").spec()); + url_generator_.GetInitiateUploadExistingFileUrl( + "0ADK06pfg", !kSetModifiedDate).spec()); EXPECT_EQ( "https://www.googleapis.com/upload/drive/v2/files/0Bz0bd074" "?uploadType=resumable", - url_generator_.GetInitiateUploadExistingFileUrl("0Bz0bd074").spec()); + url_generator_.GetInitiateUploadExistingFileUrl( + "0Bz0bd074", !kSetModifiedDate).spec()); EXPECT_EQ( "https://www.googleapis.com/upload/drive/v2/files/file%3Afile_id" "?uploadType=resumable", - url_generator_.GetInitiateUploadExistingFileUrl("file:file_id").spec()); + url_generator_.GetInitiateUploadExistingFileUrl( + "file:file_id", !kSetModifiedDate).spec()); + EXPECT_EQ( + "https://www.googleapis.com/upload/drive/v2/files/file%3Afile_id" + "?uploadType=resumable&setModifiedDate=true", + url_generator_.GetInitiateUploadExistingFileUrl( + "file:file_id", kSetModifiedDate).spec()); EXPECT_EQ( "http://127.0.0.1:12345/upload/drive/v2/files/0ADK06pfg" "?uploadType=resumable", test_url_generator_.GetInitiateUploadExistingFileUrl( - "0ADK06pfg").spec()); + "0ADK06pfg", !kSetModifiedDate).spec()); EXPECT_EQ( "http://127.0.0.1:12345/upload/drive/v2/files/0Bz0bd074" "?uploadType=resumable", test_url_generator_.GetInitiateUploadExistingFileUrl( - "0Bz0bd074").spec()); + "0Bz0bd074", !kSetModifiedDate).spec()); EXPECT_EQ( "http://127.0.0.1:12345/upload/drive/v2/files/file%3Afile_id" "?uploadType=resumable", test_url_generator_.GetInitiateUploadExistingFileUrl( - "file:file_id").spec()); + "file:file_id", !kSetModifiedDate).spec()); + EXPECT_EQ( + "http://127.0.0.1:12345/upload/drive/v2/files/file%3Afile_id" + "?uploadType=resumable&setModifiedDate=true", + test_url_generator_.GetInitiateUploadExistingFileUrl( + "file:file_id", kSetModifiedDate).spec()); } TEST_F(DriveApiUrlGeneratorTest, GenerateDownloadFileUrl) { @@ -391,4 +434,11 @@ TEST_F(DriveApiUrlGeneratorTest, GenerateDownloadFileUrl) { test_url_generator_.GenerateDownloadFileUrl("resourceId").spec()); } +TEST_F(DriveApiUrlGeneratorTest, GeneratePermissionsInsertUrl) { + EXPECT_EQ("https://www.googleapis.com/drive/v2/files/0ADK06pfg/permissions", + url_generator_.GetPermissionsInsertUrl("0ADK06pfg").spec()); + EXPECT_EQ("http://127.0.0.1:12345/drive/v2/files/file%3Aabc/permissions", + test_url_generator_.GetPermissionsInsertUrl("file:abc").spec()); +} + } // namespace google_apis diff --git a/chromium/google_apis/drive/drive_common_callbacks.h b/chromium/google_apis/drive/drive_common_callbacks.h index c31bea0358e..234c531f2b5 100644 --- a/chromium/google_apis/drive/drive_common_callbacks.h +++ b/chromium/google_apis/drive/drive_common_callbacks.h @@ -40,11 +40,6 @@ typedef base::Callback<void(GDataErrorCode error, typedef base::Callback<void(GDataErrorCode error, scoped_ptr<AppList> app_list)> AppListCallback; -// Callback used for handling UploadRangeResponse. -typedef base::Callback<void( - const UploadRangeResponse& response, - scoped_ptr<ResourceEntry> new_entry)> UploadRangeCallback; - // Callback used for authorizing an app. |open_url| is used to open the target // file with the authorized app. typedef base::Callback<void(GDataErrorCode error, diff --git a/chromium/google_apis/drive/gdata_contacts_requests.cc b/chromium/google_apis/drive/gdata_contacts_requests.cc deleted file mode 100644 index 11419af449b..00000000000 --- a/chromium/google_apis/drive/gdata_contacts_requests.cc +++ /dev/null @@ -1,115 +0,0 @@ -// 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_contacts_requests.h" - -#include "google_apis/drive/time_util.h" -#include "net/base/url_util.h" -#include "url/gurl.h" - -namespace google_apis { - -namespace { - -// URL requesting all contact groups. -const char kGetContactGroupsURL[] = - "https://www.google.com/m8/feeds/groups/default/full?alt=json"; - -// URL requesting all contacts. -// TODO(derat): Per https://goo.gl/AufHP, "The feed may not contain all of the -// user's contacts, because there's a default limit on the number of results -// returned." Decide if 10000 is reasonable or not. -const char kGetContactsURL[] = - "https://www.google.com/m8/feeds/contacts/default/full" - "?alt=json&showdeleted=true&max-results=10000"; - -// Query parameter optionally appended to |kGetContactsURL| to return contacts -// from a specific group (as opposed to all contacts). -const char kGetContactsGroupParam[] = "group"; - -// Query parameter optionally appended to |kGetContactsURL| to return only -// recently-updated contacts. -const char kGetContactsUpdatedMinParam[] = "updated-min"; - -} // namespace - -//========================== GetContactGroupsRequest ========================= - -GetContactGroupsRequest::GetContactGroupsRequest( - RequestSender* runner, - const GetDataCallback& callback) - : GetDataRequest(runner, callback) { -} - -GetContactGroupsRequest::~GetContactGroupsRequest() {} - -GURL GetContactGroupsRequest::GetURL() const { - return !feed_url_for_testing_.is_empty() ? - feed_url_for_testing_ : - GURL(kGetContactGroupsURL); -} - -//============================ GetContactsRequest ============================ - -GetContactsRequest::GetContactsRequest( - RequestSender* runner, - const std::string& group_id, - const base::Time& min_update_time, - const GetDataCallback& callback) - : GetDataRequest(runner, callback), - group_id_(group_id), - min_update_time_(min_update_time) { -} - -GetContactsRequest::~GetContactsRequest() {} - -GURL GetContactsRequest::GetURL() const { - if (!feed_url_for_testing_.is_empty()) - return GURL(feed_url_for_testing_); - - GURL url(kGetContactsURL); - - if (!group_id_.empty()) { - url = net::AppendQueryParameter(url, kGetContactsGroupParam, group_id_); - } - if (!min_update_time_.is_null()) { - std::string time_rfc3339 = util::FormatTimeAsString(min_update_time_); - url = net::AppendQueryParameter( - url, kGetContactsUpdatedMinParam, time_rfc3339); - } - return url; -} - -//========================== GetContactPhotoRequest ========================== - -GetContactPhotoRequest::GetContactPhotoRequest( - RequestSender* runner, - const GURL& photo_url, - const GetContentCallback& callback) - : UrlFetchRequestBase(runner), - photo_url_(photo_url), - callback_(callback) { -} - -GetContactPhotoRequest::~GetContactPhotoRequest() {} - -GURL GetContactPhotoRequest::GetURL() const { - return photo_url_; -} - -void GetContactPhotoRequest::ProcessURLFetchResults( - const net::URLFetcher* source) { - GDataErrorCode code = GetErrorCode(); - scoped_ptr<std::string> data(new std::string(response_writer()->data())); - callback_.Run(code, data.Pass()); - OnProcessURLFetchResultsComplete(); -} - -void GetContactPhotoRequest::RunCallbackOnPrematureFailure( - GDataErrorCode code) { - scoped_ptr<std::string> data(new std::string); - callback_.Run(code, data.Pass()); -} - -} // namespace google_apis diff --git a/chromium/google_apis/drive/gdata_contacts_requests.h b/chromium/google_apis/drive/gdata_contacts_requests.h deleted file mode 100644 index 05ce693242d..00000000000 --- a/chromium/google_apis/drive/gdata_contacts_requests.h +++ /dev/null @@ -1,102 +0,0 @@ -// 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. - -#ifndef GOOGLE_APIS_DRIVE_GDATA_CONTACTS_REQUESTS_H_ -#define GOOGLE_APIS_DRIVE_GDATA_CONTACTS_REQUESTS_H_ - -#include <string> - -#include "base/time/time.h" -#include "google_apis/drive/base_requests.h" - -namespace google_apis { - -//========================== GetContactGroupsRequest ========================= - -// This class fetches a JSON feed containing a user's contact groups. -class GetContactGroupsRequest : public GetDataRequest { - public: - GetContactGroupsRequest(RequestSender* runner, - const GetDataCallback& callback); - virtual ~GetContactGroupsRequest(); - - void set_feed_url_for_testing(const GURL& url) { - feed_url_for_testing_ = url; - } - - protected: - // Overridden from GetDataRequest. - virtual GURL GetURL() const OVERRIDE; - - private: - // If non-empty, URL of the feed to fetch. - GURL feed_url_for_testing_; - - DISALLOW_COPY_AND_ASSIGN(GetContactGroupsRequest); -}; - -//============================ GetContactsRequest ============================ - -// This class fetches a JSON feed containing a user's contacts. -class GetContactsRequest : public GetDataRequest { - public: - GetContactsRequest(RequestSender* runner, - const std::string& group_id, - const base::Time& min_update_time, - const GetDataCallback& callback); - virtual ~GetContactsRequest(); - - void set_feed_url_for_testing(const GURL& url) { - feed_url_for_testing_ = url; - } - - protected: - // Overridden from GetDataRequest. - virtual GURL GetURL() const OVERRIDE; - - private: - // If non-empty, URL of the feed to fetch. - GURL feed_url_for_testing_; - - // If non-empty, contains the ID of the group whose contacts should be - // returned. Group IDs generally look like this: - // http://www.google.com/m8/feeds/groups/user%40gmail.com/base/6 - std::string group_id_; - - // If is_null() is false, contains a minimum last-updated time that will be - // used to filter contacts. - base::Time min_update_time_; - - DISALLOW_COPY_AND_ASSIGN(GetContactsRequest); -}; - -//========================== GetContactPhotoRequest ========================== - -// This class fetches a contact's photo. -class GetContactPhotoRequest : public UrlFetchRequestBase { - public: - GetContactPhotoRequest(RequestSender* runner, - const GURL& photo_url, - const GetContentCallback& callback); - virtual ~GetContactPhotoRequest(); - - protected: - // Overridden from UrlFetchRequestBase. - virtual GURL GetURL() const OVERRIDE; - virtual void ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE; - virtual void RunCallbackOnPrematureFailure(GDataErrorCode code) OVERRIDE; - - private: - // Location of the photo to fetch. - GURL photo_url_; - - // Callback to which the photo data is passed. - GetContentCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(GetContactPhotoRequest); -}; - -} // namespace google_apis - -#endif // GOOGLE_APIS_DRIVE_GDATA_CONTACTS_REQUESTS_H_ diff --git a/chromium/google_apis/drive/gdata_wapi_parser.cc b/chromium/google_apis/drive/gdata_wapi_parser.cc index 82f9d43151f..9c50e5ab524 100644 --- a/chromium/google_apis/drive/gdata_wapi_parser.cc +++ b/chromium/google_apis/drive/gdata_wapi_parser.cc @@ -46,23 +46,6 @@ const char kFeedLinkField[] = "gd$feedLink"; const char kFileNameField[] = "docs$filename.$t"; const char kHrefField[] = "href"; const char kIDField[] = "id.$t"; -const char kInstalledAppField[] = "docs$installedApp"; -const char kInstalledAppNameField[] = "docs$installedAppName"; -const char kInstalledAppIdField[] = "docs$installedAppId"; -const char kInstalledAppIconField[] = "docs$installedAppIcon"; -const char kInstalledAppIconCategoryField[] = "docs$installedAppIconCategory"; -const char kInstalledAppIconSizeField[] = "docs$installedAppIconSize"; -const char kInstalledAppObjectTypeField[] = "docs$installedAppObjectType"; -const char kInstalledAppPrimaryFileExtensionField[] = - "docs$installedAppPrimaryFileExtension"; -const char kInstalledAppPrimaryMimeTypeField[] = - "docs$installedAppPrimaryMimeType"; -const char kInstalledAppSecondaryFileExtensionField[] = - "docs$installedAppSecondaryFileExtension"; -const char kInstalledAppSecondaryMimeTypeField[] = - "docs$installedAppSecondaryMimeType"; -const char kInstalledAppSupportsCreateField[] = - "docs$installedAppSupportsCreate"; const char kItemsPerPageField[] = "openSearch$itemsPerPage.$t"; const char kLabelField[] = "label"; const char kLargestChangestampField[] = "docs$largestChangestamp.value"; @@ -71,8 +54,6 @@ const char kLinkField[] = "link"; const char kMD5Field[] = "docs$md5Checksum.$t"; const char kNameField[] = "name.$t"; const char kPublishedField[] = "published.$t"; -const char kQuotaBytesTotalField[] = "gd$quotaBytesTotal.$t"; -const char kQuotaBytesUsedField[] = "gd$quotaBytesUsed.$t"; const char kRelField[] = "rel"; const char kRemovedField[] = "docs$removed"; const char kResourceIdField[] = "gd$resourceId.$t"; @@ -81,7 +62,6 @@ const char kSizeField[] = "docs$size.$t"; const char kSrcField[] = "src"; const char kStartIndexField[] = "openSearch$startIndex.$t"; const char kSuggestedFileNameField[] = "docs$suggestedFilename.$t"; -const char kTField[] = "$t"; const char kTermField[] = "term"; const char kTitleField[] = "title"; const char kTitleTField[] = "title.$t"; @@ -186,17 +166,6 @@ const CategoryTypeMap kCategoryTypeMap[] = { { Category::CATEGORY_LABEL, "http://schemas.google.com/g/2005/labels" }, }; -struct AppIconCategoryMap { - AppIcon::IconCategory category; - const char* category_name; -}; - -const AppIconCategoryMap kAppIconCategoryMap[] = { - { AppIcon::ICON_DOCUMENT, "document" }, - { AppIcon::ICON_APPLICATION, "application" }, - { AppIcon::ICON_SHARED_DOCUMENT, "documentShared" }, -}; - // Converts |url_string| to |result|. Always returns true to be used // for JSONValueConverter::RegisterCustomField method. // TODO(mukai): make it return false in case of invalid |url_string|. @@ -205,17 +174,6 @@ bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) { return true; } -// Converts boolean string values like "true" into bool. -bool GetBoolFromString(const base::StringPiece& value, bool* result) { - *result = (value == "true"); - return true; -} - -bool SortBySize(const InstalledApp::IconList::value_type& a, - const InstalledApp::IconList::value_type& b) { - return a.first < b.first; -} - } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -378,49 +336,6 @@ void Content::RegisterJSONConverter( } //////////////////////////////////////////////////////////////////////////////// -// AppIcon implementation - -AppIcon::AppIcon() : category_(AppIcon::ICON_UNKNOWN), icon_side_length_(0) { -} - -AppIcon::~AppIcon() { -} - -// static -void AppIcon::RegisterJSONConverter( - base::JSONValueConverter<AppIcon>* converter) { - converter->RegisterCustomField<AppIcon::IconCategory>( - kInstalledAppIconCategoryField, - &AppIcon::category_, - &AppIcon::GetIconCategory); - converter->RegisterCustomField<int>(kInstalledAppIconSizeField, - &AppIcon::icon_side_length_, - base::StringToInt); - converter->RegisterRepeatedMessage(kLinkField, &AppIcon::links_); -} - -GURL AppIcon::GetIconURL() const { - for (size_t i = 0; i < links_.size(); ++i) { - if (links_[i]->type() == Link::LINK_ICON) - return links_[i]->href(); - } - return GURL(); -} - -// static -bool AppIcon::GetIconCategory(const base::StringPiece& category, - AppIcon::IconCategory* result) { - for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) { - if (category == kAppIconCategoryMap[i].category_name) { - *result = kAppIconCategoryMap[i].category; - return true; - } - } - DVLOG(1) << "Unknown icon category " << category; - return false; -} - -//////////////////////////////////////////////////////////////////////////////// // CommonMetadata implementation CommonMetadata::CommonMetadata() { @@ -523,9 +438,10 @@ void ResourceEntry::RegisterJSONConverter( // ImageMediaMetadata fields are not supported by WAPI. } -std::string ResourceEntry::GetHostedDocumentExtension() const { +// static +std::string ResourceEntry::GetHostedDocumentExtension(DriveEntryKind kind) { for (size_t i = 0; i < arraysize(kEntryKindMap); i++) { - if (kEntryKindMap[i].kind == kind_) { + if (kEntryKindMap[i].kind == kind) { if (kEntryKindMap[i].extension) return std::string(kEntryKindMap[i].extension); else @@ -536,19 +452,25 @@ std::string ResourceEntry::GetHostedDocumentExtension() const { } // static +DriveEntryKind ResourceEntry::GetEntryKindFromExtension( + const std::string& extension) { + for (size_t i = 0; i < arraysize(kEntryKindMap); ++i) { + const char* document_extension = kEntryKindMap[i].extension; + if (document_extension && extension == document_extension) + return kEntryKindMap[i].kind; + } + return ENTRY_KIND_UNKNOWN; +} + +// static int ResourceEntry::ClassifyEntryKindByFileExtension( const base::FilePath& file_path) { #if defined(OS_WIN) - std::string file_extension = WideToUTF8(file_path.Extension()); + std::string file_extension = base::WideToUTF8(file_path.Extension()); #else std::string file_extension = file_path.Extension(); #endif - for (size_t i = 0; i < arraysize(kEntryKindMap); ++i) { - const char* document_extension = kEntryKindMap[i].extension; - if (document_extension && file_extension == document_extension) - return ClassifyEntryKind(kEntryKindMap[i].kind); - } - return 0; + return ClassifyEntryKind(GetEntryKindFromExtension(file_extension)); } // static @@ -742,142 +664,4 @@ void ResourceList::ReleaseEntries(std::vector<ResourceEntry*>* entries) { entries_.release(entries); } -//////////////////////////////////////////////////////////////////////////////// -// InstalledApp implementation - -InstalledApp::InstalledApp() : supports_create_(false) { -} - -InstalledApp::~InstalledApp() { -} - -InstalledApp::IconList InstalledApp::GetIconsForCategory( - AppIcon::IconCategory category) const { - IconList result; - - for (ScopedVector<AppIcon>::const_iterator icon_iter = app_icons_.begin(); - icon_iter != app_icons_.end(); ++icon_iter) { - if ((*icon_iter)->category() != category) - continue; - GURL icon_url = (*icon_iter)->GetIconURL(); - if (icon_url.is_empty()) - continue; - result.push_back(std::make_pair((*icon_iter)->icon_side_length(), - icon_url)); - } - - // Return a sorted list, smallest to largest. - std::sort(result.begin(), result.end(), SortBySize); - return result; -} - -GURL InstalledApp::GetProductUrl() const { - for (ScopedVector<Link>::const_iterator it = links_.begin(); - it != links_.end(); ++it) { - const Link* link = *it; - if (link->type() == Link::LINK_PRODUCT) - return link->href(); - } - return GURL(); -} - -// static -bool InstalledApp::GetValueString(const base::Value* value, - std::string* result) { - const base::DictionaryValue* dict = NULL; - if (!value->GetAsDictionary(&dict)) - return false; - - if (!dict->GetString(kTField, result)) - return false; - - return true; -} - -// static -void InstalledApp::RegisterJSONConverter( - base::JSONValueConverter<InstalledApp>* converter) { - converter->RegisterRepeatedMessage(kInstalledAppIconField, - &InstalledApp::app_icons_); - converter->RegisterStringField(kInstalledAppIdField, - &InstalledApp::app_id_); - converter->RegisterStringField(kInstalledAppNameField, - &InstalledApp::app_name_); - converter->RegisterStringField(kInstalledAppObjectTypeField, - &InstalledApp::object_type_); - converter->RegisterCustomField<bool>(kInstalledAppSupportsCreateField, - &InstalledApp::supports_create_, - &GetBoolFromString); - converter->RegisterRepeatedCustomValue(kInstalledAppPrimaryMimeTypeField, - &InstalledApp::primary_mimetypes_, - &GetValueString); - converter->RegisterRepeatedCustomValue(kInstalledAppSecondaryMimeTypeField, - &InstalledApp::secondary_mimetypes_, - &GetValueString); - converter->RegisterRepeatedCustomValue(kInstalledAppPrimaryFileExtensionField, - &InstalledApp::primary_extensions_, - &GetValueString); - converter->RegisterRepeatedCustomValue( - kInstalledAppSecondaryFileExtensionField, - &InstalledApp::secondary_extensions_, - &GetValueString); - converter->RegisterRepeatedMessage(kLinkField, &InstalledApp::links_); -} - -//////////////////////////////////////////////////////////////////////////////// -// AccountMetadata implementation - -AccountMetadata::AccountMetadata() - : quota_bytes_total_(0), - quota_bytes_used_(0), - largest_changestamp_(0) { -} - -AccountMetadata::~AccountMetadata() { -} - -// static -void AccountMetadata::RegisterJSONConverter( - base::JSONValueConverter<AccountMetadata>* converter) { - converter->RegisterCustomField<int64>( - kQuotaBytesTotalField, - &AccountMetadata::quota_bytes_total_, - &base::StringToInt64); - converter->RegisterCustomField<int64>( - kQuotaBytesUsedField, - &AccountMetadata::quota_bytes_used_, - &base::StringToInt64); - converter->RegisterCustomField<int64>( - kLargestChangestampField, - &AccountMetadata::largest_changestamp_, - &base::StringToInt64); - converter->RegisterRepeatedMessage(kInstalledAppField, - &AccountMetadata::installed_apps_); -} - -// static -scoped_ptr<AccountMetadata> AccountMetadata::CreateFrom( - const base::Value& value) { - scoped_ptr<AccountMetadata> metadata(new AccountMetadata()); - const base::DictionaryValue* dictionary = NULL; - const base::Value* entry = NULL; - if (!value.GetAsDictionary(&dictionary) || - !dictionary->Get(kEntryField, &entry) || - !metadata->Parse(*entry)) { - LOG(ERROR) << "Unable to create: Invalid account metadata feed!"; - return scoped_ptr<AccountMetadata>(); - } - - return metadata.Pass(); -} - -bool AccountMetadata::Parse(const base::Value& value) { - base::JSONValueConverter<AccountMetadata> converter; - if (!converter.Convert(value, this)) { - LOG(ERROR) << "Unable to parse: Invalid account metadata feed!"; - return false; - } - return true; -} - } // namespace google_apis diff --git a/chromium/google_apis/drive/gdata_wapi_parser.h b/chromium/google_apis/drive/gdata_wapi_parser.h index 0c89c11b09e..1081dbcf9cf 100644 --- a/chromium/google_apis/drive/gdata_wapi_parser.h +++ b/chromium/google_apis/drive/gdata_wapi_parser.h @@ -251,60 +251,6 @@ class Content { std::string mime_type_; }; -// This stores a representation of an application icon as registered with the -// installed applications section of the account metadata feed. There can be -// multiple icons registered for each application, differing in size, category -// and MIME type. -class AppIcon { - public: - enum IconCategory { - ICON_UNKNOWN, // Uninitialized state - ICON_DOCUMENT, // Document icon for various MIME types - ICON_APPLICATION, // Application icon for various MIME types - ICON_SHARED_DOCUMENT, // Icon for documents that are shared from other - // users. - }; - - AppIcon(); - ~AppIcon(); - - // Registers the mapping between JSON field names and the members in - // this class. - static void RegisterJSONConverter( - base::JSONValueConverter<AppIcon>* converter); - - // Category of the icon. - IconCategory category() const { return category_; } - - // Size in pixels of one side of the icon (icons are always square). - int icon_side_length() const { return icon_side_length_; } - - // Get a list of links available for this AppIcon. - const ScopedVector<Link>& links() const { return links_; } - - // Get the icon URL from the internal list of links. Returns the first - // icon URL found in the list. - GURL GetIconURL() const; - - void set_category(IconCategory category) { category_ = category; } - void set_icon_side_length(int icon_side_length) { - icon_side_length_ = icon_side_length; - } - void set_links(ScopedVector<Link> links) { links_ = links.Pass(); } - - private: - // Extracts the icon category from the given string. Returns false and does - // not change |result| when |scheme| has an unrecognizable value. - static bool GetIconCategory(const base::StringPiece& category, - IconCategory* result); - - IconCategory category_; - int icon_side_length_; - ScopedVector<Link> links_; - - DISALLOW_COPY_AND_ASSIGN(AppIcon); -}; - // Base class for feed entries. This class defines fields commonly used by // various feeds. class CommonMetadata { @@ -464,13 +410,17 @@ class ResourceEntry : public CommonMetadata { // If doesn't exist, then equals -1. int64 image_rotation() const { return image_rotation_; } + // The time of this modification. + // Note: This property is filled only when converted from ChangeResource. + const base::Time& modification_date() const { return modification_date_; } + // Text version of resource entry kind. Returns an empty string for // unknown entry kind. std::string GetEntryKindText() const; // Returns preferred file extension for hosted documents. If entry is not // a hosted document, this call returns an empty string. - std::string GetHostedDocumentExtension() const; + static std::string GetHostedDocumentExtension(DriveEntryKind kind); // True if resource entry is remotely hosted. bool is_hosted_document() const { @@ -509,6 +459,9 @@ class ResourceEntry : public CommonMetadata { KIND_OF_FILE = 1 << 4, }; + // Returns the kind enum corresponding to the extension in form ".xxx". + static DriveEntryKind GetEntryKindFromExtension(const std::string& extension); + // Classifies the EntryKind. The returned value is a bitmask of // EntryKindClass. For example, DOCUMENT is classified as // KIND_OF_HOSTED_DOCUMENT and KIND_OF_GOOGLE_DOCUMENT, hence the returned @@ -554,6 +507,9 @@ class ResourceEntry : public CommonMetadata { void set_image_rotation(int64 image_rotation) { image_rotation_ = image_rotation; } + void set_modification_date(const base::Time& modification_date) { + modification_date_ = modification_date; + } // Fills the remaining fields where JSONValueConverter cannot catch. // Currently, sets |kind_| and |labels_| based on the |categories_| in the @@ -592,6 +548,8 @@ class ResourceEntry : public CommonMetadata { int64 image_height_; int64 image_rotation_; + base::Time modification_date_; + DISALLOW_COPY_AND_ASSIGN(ResourceEntry); }; @@ -682,185 +640,6 @@ class ResourceList : public CommonMetadata { DISALLOW_COPY_AND_ASSIGN(ResourceList); }; -// Metadata representing installed Google Drive application. -class InstalledApp { - public: - typedef std::vector<std::pair<int, GURL> > IconList; - - InstalledApp(); - virtual ~InstalledApp(); - - // WebApp name. - const std::string& app_name() const { return app_name_; } - - // Drive app id - const std::string& app_id() const { return app_id_; } - - // Object (file) type name that is generated by this WebApp. - const std::string& object_type() const { return object_type_; } - - // True if WebApp supports creation of new file instances. - bool supports_create() const { return supports_create_; } - - // List of primary mime types supported by this WebApp. Primary status should - // trigger this WebApp becoming the default handler of file instances that - // have these mime types. - const ScopedVector<std::string>& primary_mimetypes() const { - return primary_mimetypes_; - } - - // List of secondary mime types supported by this WebApp. Secondary status - // should make this WebApp show up in "Open with..." pop-up menu of the - // default action menu for file with matching mime types. - const ScopedVector<std::string>& secondary_mimetypes() const { - return secondary_mimetypes_; - } - - // List of primary file extensions supported by this WebApp. Primary status - // should trigger this WebApp becoming the default handler of file instances - // that match these extensions. - const ScopedVector<std::string>& primary_extensions() const { - return primary_extensions_; - } - - // List of secondary file extensions supported by this WebApp. Secondary - // status should make this WebApp show up in "Open with..." pop-up menu of the - // default action menu for file with matching extensions. - const ScopedVector<std::string>& secondary_extensions() const { - return secondary_extensions_; - } - - // List of entry links. - const ScopedVector<Link>& links() const { return links_; } - - // Returns a list of icons associated with this installed application. - const ScopedVector<AppIcon>& app_icons() const { - return app_icons_; - } - - // Convenience function for getting the icon URLs for a particular |category| - // of icon. Icons are returned in a sorted list, from smallest to largest. - IconList GetIconsForCategory(AppIcon::IconCategory category) const; - - // Retrieves product URL from the link collection. - GURL GetProductUrl() const; - - // Registers the mapping between JSON field names and the members in - // this class. - static void RegisterJSONConverter( - base::JSONValueConverter<InstalledApp>* converter); - - void set_app_id(const std::string& app_id) { app_id_ = app_id; } - void set_app_name(const std::string& app_name) { app_name_ = app_name; } - void set_object_type(const std::string& object_type) { - object_type_ = object_type; - } - void set_supports_create(bool supports_create) { - supports_create_ = supports_create; - } - void set_primary_mimetypes( - ScopedVector<std::string> primary_mimetypes) { - primary_mimetypes_ = primary_mimetypes.Pass(); - } - void set_secondary_mimetypes( - ScopedVector<std::string> secondary_mimetypes) { - secondary_mimetypes_ = secondary_mimetypes.Pass(); - } - void set_primary_extensions( - ScopedVector<std::string> primary_extensions) { - primary_extensions_ = primary_extensions.Pass(); - } - void set_secondary_extensions( - ScopedVector<std::string> secondary_extensions) { - secondary_extensions_ = secondary_extensions.Pass(); - } - void set_links(ScopedVector<Link> links) { - links_ = links.Pass(); - } - void set_app_icons(ScopedVector<AppIcon> app_icons) { - app_icons_ = app_icons.Pass(); - } - - private: - // Extracts "$t" value from the dictionary |value| and returns it in |result|. - // If the string value can't be found, it returns false. - static bool GetValueString(const base::Value* value, - std::string* result); - - std::string app_id_; - std::string app_name_; - std::string object_type_; - bool supports_create_; - ScopedVector<std::string> primary_mimetypes_; - ScopedVector<std::string> secondary_mimetypes_; - ScopedVector<std::string> primary_extensions_; - ScopedVector<std::string> secondary_extensions_; - ScopedVector<Link> links_; - ScopedVector<AppIcon> app_icons_; -}; - -// Account metadata feed represents the metadata object attached to the user's -// account. -class AccountMetadata { - public: - AccountMetadata(); - virtual ~AccountMetadata(); - - // Creates feed from parsed JSON Value. You should call this - // instead of instantiating JSONValueConverter by yourself because - // this method does some post-process for some fields. See - // FillRemainingFields comment and implementation in ResourceEntry - // class for the details. - static scoped_ptr<AccountMetadata> CreateFrom(const base::Value& value); - - int64 quota_bytes_total() const { - return quota_bytes_total_; - } - - int64 quota_bytes_used() const { - return quota_bytes_used_; - } - - int64 largest_changestamp() const { - return largest_changestamp_; - } - - const ScopedVector<InstalledApp>& installed_apps() const { - return installed_apps_; - } - - void set_quota_bytes_total(int64 quota_bytes_total) { - quota_bytes_total_ = quota_bytes_total; - } - void set_quota_bytes_used(int64 quota_bytes_used) { - quota_bytes_used_ = quota_bytes_used; - } - void set_largest_changestamp(int64 largest_changestamp) { - largest_changestamp_ = largest_changestamp; - } - void set_installed_apps(ScopedVector<InstalledApp> installed_apps) { - installed_apps_ = installed_apps.Pass(); - } - - // Registers the mapping between JSON field names and the members in - // this class. - static void RegisterJSONConverter( - base::JSONValueConverter<AccountMetadata>* converter); - - private: - // Parses and initializes data members from content of |value|. - // Return false if parsing fails. - bool Parse(const base::Value& value); - - int64 quota_bytes_total_; - int64 quota_bytes_used_; - int64 largest_changestamp_; - ScopedVector<InstalledApp> installed_apps_; - - DISALLOW_COPY_AND_ASSIGN(AccountMetadata); -}; - - } // namespace google_apis #endif // GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_ diff --git a/chromium/google_apis/drive/gdata_wapi_parser_unittest.cc b/chromium/google_apis/drive/gdata_wapi_parser_unittest.cc index 58728d129ba..6655aed8cb0 100644 --- a/chromium/google_apis/drive/gdata_wapi_parser_unittest.cc +++ b/chromium/google_apis/drive/gdata_wapi_parser_unittest.cc @@ -17,8 +17,6 @@ namespace google_apis { -// TODO(nhiroki): Move json files to out of 'chromeos' directory -// (http://crbug.com/149788). // Test document feed parsing. TEST(GDataWAPIParserTest, ResourceListJsonParser) { std::string error; @@ -237,73 +235,6 @@ TEST(GDataWAPIParserTest, ResourceEntryJsonParser) { EXPECT_EQ(-1, entry->image_rotation()); } -TEST(GDataWAPIParserTest, AccountMetadataParser) { - scoped_ptr<base::Value> document = - test_util::LoadJSONFile("gdata/account_metadata.json"); - ASSERT_TRUE(document.get()); - base::DictionaryValue* document_dict = NULL; - base::DictionaryValue* entry_value = NULL; - ASSERT_TRUE(document->GetAsDictionary(&document_dict)); - ASSERT_TRUE(document_dict->GetDictionary(std::string("entry"), &entry_value)); - ASSERT_TRUE(entry_value); - - scoped_ptr<AccountMetadata> metadata( - AccountMetadata::CreateFrom(*document)); - ASSERT_TRUE(metadata.get()); - EXPECT_EQ(GG_LONGLONG(6789012345), metadata->quota_bytes_used()); - EXPECT_EQ(GG_LONGLONG(9876543210), metadata->quota_bytes_total()); - EXPECT_EQ(654321, metadata->largest_changestamp()); - EXPECT_EQ(2U, metadata->installed_apps().size()); - const InstalledApp* first_app = metadata->installed_apps()[0]; - const InstalledApp* second_app = metadata->installed_apps()[1]; - - ASSERT_TRUE(first_app); - EXPECT_EQ("Drive App 1", first_app->app_name()); - EXPECT_EQ("Drive App Object 1", first_app->object_type()); - EXPECT_TRUE(first_app->supports_create()); - EXPECT_EQ("https://chrome.google.com/webstore/detail/abcdefabcdef", - first_app->GetProductUrl().spec()); - - ASSERT_EQ(2U, first_app->primary_mimetypes().size()); - EXPECT_EQ("application/test_type_1", - *first_app->primary_mimetypes()[0]); - EXPECT_EQ("application/vnd.google-apps.drive-sdk.11111111", - *first_app->primary_mimetypes()[1]); - - ASSERT_EQ(1U, first_app->secondary_mimetypes().size()); - EXPECT_EQ("image/jpeg", *first_app->secondary_mimetypes()[0]); - - ASSERT_EQ(2U, first_app->primary_extensions().size()); - EXPECT_EQ("ext_1", *first_app->primary_extensions()[0]); - EXPECT_EQ("ext_2", *first_app->primary_extensions()[1]); - - ASSERT_EQ(1U, first_app->secondary_extensions().size()); - EXPECT_EQ("ext_3", *first_app->secondary_extensions()[0]); - - ASSERT_EQ(1U, first_app->app_icons().size()); - EXPECT_EQ(AppIcon::ICON_DOCUMENT, first_app->app_icons()[0]->category()); - EXPECT_EQ(16, first_app->app_icons()[0]->icon_side_length()); - GURL icon_url = first_app->app_icons()[0]->GetIconURL(); - EXPECT_EQ("https://www.google.com/images/srpr/logo3w.png", icon_url.spec()); - InstalledApp::IconList icons = - first_app->GetIconsForCategory(AppIcon::ICON_DOCUMENT); - EXPECT_EQ("https://www.google.com/images/srpr/logo3w.png", - icons[0].second.spec()); - icons = first_app->GetIconsForCategory(AppIcon::ICON_SHARED_DOCUMENT); - EXPECT_TRUE(icons.empty()); - - ASSERT_TRUE(second_app); - EXPECT_EQ("Drive App 2", second_app->app_name()); - EXPECT_EQ("Drive App Object 2", second_app->object_type()); - EXPECT_EQ("https://chrome.google.com/webstore/detail/deadbeefdeadbeef", - second_app->GetProductUrl().spec()); - EXPECT_FALSE(second_app->supports_create()); - EXPECT_EQ(2U, second_app->primary_mimetypes().size()); - EXPECT_EQ(0U, second_app->secondary_mimetypes().size()); - EXPECT_EQ(1U, second_app->primary_extensions().size()); - EXPECT_EQ(0U, second_app->secondary_extensions().size()); -} - TEST(GDataWAPIParserTest, ClassifyEntryKindByFileExtension) { EXPECT_EQ( ResourceEntry::KIND_OF_GOOGLE_DOCUMENT | diff --git a/chromium/google_apis/drive/gdata_wapi_requests.cc b/chromium/google_apis/drive/gdata_wapi_requests.cc index 1ae8a95ef08..42592172075 100644 --- a/chromium/google_apis/drive/gdata_wapi_requests.cc +++ b/chromium/google_apis/drive/gdata_wapi_requests.cc @@ -4,202 +4,10 @@ #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( @@ -222,459 +30,4 @@ GURL GetResourceEntryRequest::GetURL() const { 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 diff --git a/chromium/google_apis/drive/gdata_wapi_requests.h b/chromium/google_apis/drive/gdata_wapi_requests.h index a4587d7628b..7e64906ca48 100644 --- a/chromium/google_apis/drive/gdata_wapi_requests.h +++ b/chromium/google_apis/drive/gdata_wapi_requests.h @@ -6,96 +6,12 @@ #define GOOGLE_APIS_DRIVE_GDATA_WAPI_REQUESTS_H_ #include <string> -#include <vector> #include "google_apis/drive/base_requests.h" -#include "google_apis/drive/drive_common_callbacks.h" #include "google_apis/drive/gdata_wapi_url_generator.h" namespace google_apis { -class AccountMetadata; -class GDataWapiUrlGenerator; -class ResourceEntry; - -//============================ GetResourceListRequest ======================== - -// This class performs the request for fetching a resource list. -class GetResourceListRequest : public GetDataRequest { - public: - // override_url: - // If empty, a hard-coded base URL of the WAPI server is used to fetch - // the first page of the feed. This parameter is used for fetching 2nd - // page and onward. - // - // start_changestamp: - // This parameter specifies the starting point of a delta feed or 0 if a - // full feed is necessary. - // - // search_string: - // If non-empty, fetches a list of resources that match the search - // string. - // - // directory_resource_id: - // If non-empty, fetches a list of resources in a particular directory. - // - // callback: - // Called once the feed is fetched. Must not be null. - 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); - virtual ~GetResourceListRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const GURL override_url_; - const int64 start_changestamp_; - const std::string search_string_; - const std::string directory_resource_id_; - - DISALLOW_COPY_AND_ASSIGN(GetResourceListRequest); -}; - -//============================ SearchByTitleRequest ========================== - -// This class performs the request for searching resources by title. -class SearchByTitleRequest : public GetDataRequest { - public: - // title: the search query. - // - // directory_resource_id: If given (non-empty), the search target is - // directly under the directory with the |directory_resource_id|. - // If empty, the search target is all the existing resources. - // - // callback: - // Called once the feed is fetched. Must not be null. - SearchByTitleRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const std::string& title, - const std::string& directory_resource_id, - const GetResourceListCallback& callback); - virtual ~SearchByTitleRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string title_; - const std::string directory_resource_id_; - - DISALLOW_COPY_AND_ASSIGN(SearchByTitleRequest); -}; - //========================= GetResourceEntryRequest ========================== // This class performs the request for fetching a single resource entry. @@ -123,364 +39,6 @@ class GetResourceEntryRequest : public GetDataRequest { DISALLOW_COPY_AND_ASSIGN(GetResourceEntryRequest); }; -//========================= GetAccountMetadataRequest ======================== - -// Callback used for GetAccountMetadata(). -typedef base::Callback<void(GDataErrorCode error, - scoped_ptr<AccountMetadata> account_metadata)> - GetAccountMetadataCallback; - -// This class performs the request for fetching account metadata. -class GetAccountMetadataRequest : public GetDataRequest { - public: - // If |include_installed_apps| is set to true, the result should include - // the list of installed third party applications. - // |callback| must not be null. - GetAccountMetadataRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const GetAccountMetadataCallback& callback, - bool include_installed_apps); - virtual ~GetAccountMetadataRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const bool include_installed_apps_; - - DISALLOW_COPY_AND_ASSIGN(GetAccountMetadataRequest); -}; - -//=========================== DeleteResourceRequest ========================== - -// This class performs the request for deleting a resource. -// -// In WAPI, "gd:deleted" means that the resource was put in the trash, and -// "docs:removed" means its permanently gone. Since what the class does is to -// put the resource into trash, we have chosen "Delete" in the name, even though -// we are preferring the term "Remove" in drive/google_api code. -class DeleteResourceRequest : public EntryActionRequest { - public: - // |callback| must not be null. - DeleteResourceRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const EntryActionCallback& callback, - const std::string& resource_id, - const std::string& etag); - virtual ~DeleteResourceRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string resource_id_; - const std::string etag_; - - DISALLOW_COPY_AND_ASSIGN(DeleteResourceRequest); -}; - -//========================== CreateDirectoryRequest ========================== - -// This class performs the request for creating a directory. -class CreateDirectoryRequest : public GetDataRequest { - public: - // A new directory will be created under a directory specified by - // |parent_resource_id|. If this parameter is empty, a new directory will - // be created in the root directory. - // |callback| must not be null. - CreateDirectoryRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const GetDataCallback& callback, - const std::string& parent_resource_id, - const std::string& directory_title); - virtual ~CreateDirectoryRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string parent_resource_id_; - const std::string directory_title_; - - DISALLOW_COPY_AND_ASSIGN(CreateDirectoryRequest); -}; - -//=========================== RenameResourceRequest ========================== - -// This class performs the request for renaming a document/file/directory. -class RenameResourceRequest : public EntryActionRequest { - public: - // |callback| must not be null. - RenameResourceRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const EntryActionCallback& callback, - const std::string& resource_id, - const std::string& new_title); - virtual ~RenameResourceRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; - virtual GURL GetURL() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string resource_id_; - const std::string new_title_; - - DISALLOW_COPY_AND_ASSIGN(RenameResourceRequest); -}; - -//=========================== AuthorizeAppRequest ========================== - -// This class performs the request for authorizing an application specified -// by |app_id| to access a document specified by |resource_id|. -class AuthorizeAppRequest : public GetDataRequest { - public: - // |callback| must not be null. - AuthorizeAppRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const AuthorizeAppCallback& callback, - const std::string& resource_id, - const std::string& app_id); - virtual ~AuthorizeAppRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; - virtual GURL GetURL() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string resource_id_; - const std::string app_id_; - - DISALLOW_COPY_AND_ASSIGN(AuthorizeAppRequest); -}; - -//======================= AddResourceToDirectoryRequest ====================== - -// This class performs the request for adding a document/file/directory -// to a directory. -class AddResourceToDirectoryRequest : public EntryActionRequest { - public: - // |callback| must not be null. - AddResourceToDirectoryRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const EntryActionCallback& callback, - const std::string& parent_resource_id, - const std::string& resource_id); - virtual ~AddResourceToDirectoryRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string parent_resource_id_; - const std::string resource_id_; - - DISALLOW_COPY_AND_ASSIGN(AddResourceToDirectoryRequest); -}; - -//==================== RemoveResourceFromDirectoryRequest ==================== - -// This class performs the request for removing a document/file/directory -// from a directory. -class RemoveResourceFromDirectoryRequest : public EntryActionRequest { - public: - // |callback| must not be null. - RemoveResourceFromDirectoryRequest(RequestSender* sender, - const GDataWapiUrlGenerator& url_generator, - const EntryActionCallback& callback, - const std::string& parent_resource_id, - const std::string& resource_id); - virtual ~RemoveResourceFromDirectoryRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string resource_id_; - const std::string parent_resource_id_; - - DISALLOW_COPY_AND_ASSIGN(RemoveResourceFromDirectoryRequest); -}; - -//======================= InitiateUploadNewFileRequest ======================= - -// This class performs the request for initiating the upload of a new file. -class InitiateUploadNewFileRequest : public InitiateUploadRequestBase { - public: - // |title| should be set. - // |parent_upload_url| should be the upload_url() of the parent directory. - // (resumable-create-media URL) - // See also the comments of InitiateUploadRequestBase for more details - // about the other parameters. - 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); - virtual ~InitiateUploadNewFileRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string parent_resource_id_; - const std::string title_; - - DISALLOW_COPY_AND_ASSIGN(InitiateUploadNewFileRequest); -}; - -//==================== InitiateUploadExistingFileRequest ===================== - -// This class performs the request for initiating the upload of an existing -// file. -class InitiateUploadExistingFileRequest - : public InitiateUploadRequestBase { - public: - // |upload_url| should be the upload_url() of the file - // (resumable-create-media URL) - // |etag| should be set if it is available to detect the upload confliction. - // See also the comments of InitiateUploadRequestBase for more details - // about the other parameters. - 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); - virtual ~InitiateUploadExistingFileRequest(); - - protected: - // UrlFetchRequestBase overrides. - virtual GURL GetURL() const OVERRIDE; - virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE; - virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE; - virtual bool GetContentData(std::string* upload_content_type, - std::string* upload_content) OVERRIDE; - - private: - const GDataWapiUrlGenerator url_generator_; - const std::string resource_id_; - const std::string etag_; - - DISALLOW_COPY_AND_ASSIGN(InitiateUploadExistingFileRequest); -}; - -//============================ ResumeUploadRequest =========================== - -// Performs the request for resuming the upload of a file. -class ResumeUploadRequest : public ResumeUploadRequestBase { - public: - // See also ResumeUploadRequestBase's comment for parameters meaning. - // |callback| must not be null. - 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); - virtual ~ResumeUploadRequest(); - - protected: - // UploadRangeRequestBase overrides. - virtual void OnRangeRequestComplete( - const UploadRangeResponse& response, - scoped_ptr<base::Value> value) OVERRIDE; - // content::UrlFetcherDelegate overrides. - virtual void OnURLFetchUploadProgress(const net::URLFetcher* source, - int64 current, int64 total) OVERRIDE; - - private: - const UploadRangeCallback callback_; - const ProgressCallback progress_callback_; - - DISALLOW_COPY_AND_ASSIGN(ResumeUploadRequest); -}; - -//========================== GetUploadStatusRequest ========================== - -// Performs the request to request the current upload status of a file. -class GetUploadStatusRequest : public GetUploadStatusRequestBase { - public: - // See also GetUploadStatusRequestBase's comment for parameters meaning. - // |callback| must not be null. - GetUploadStatusRequest(RequestSender* sender, - const UploadRangeCallback& callback, - const GURL& upload_url, - int64 content_length); - virtual ~GetUploadStatusRequest(); - - protected: - // UploadRangeRequestBase overrides. - virtual void OnRangeRequestComplete( - const UploadRangeResponse& response, - scoped_ptr<base::Value> value) OVERRIDE; - - private: - const UploadRangeCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(GetUploadStatusRequest); -}; - - -//========================== DownloadFileRequest ========================== - -// This class performs the request for downloading of a specified file. -class DownloadFileRequest : public DownloadFileRequestBase { - public: - // See also DownloadFileRequestBase's comment for parameters meaning. - 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); - virtual ~DownloadFileRequest(); - - DISALLOW_COPY_AND_ASSIGN(DownloadFileRequest); -}; - } // namespace google_apis #endif // GOOGLE_APIS_DRIVE_GDATA_WAPI_REQUESTS_H_ diff --git a/chromium/google_apis/drive/gdata_wapi_requests_unittest.cc b/chromium/google_apis/drive/gdata_wapi_requests_unittest.cc index e302f23f1e8..2c39745184a 100644 --- a/chromium/google_apis/drive/gdata_wapi_requests_unittest.cc +++ b/chromium/google_apis/drive/gdata_wapi_requests_unittest.cc @@ -2,19 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <algorithm> -#include <map> - #include "base/bind.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/values.h" #include "google_apis/drive/dummy_auth_service.h" #include "google_apis/drive/gdata_wapi_parser.h" @@ -34,14 +24,9 @@ namespace google_apis { namespace { const char kTestUserAgent[] = "test-user-agent"; -const char kTestETag[] = "test_etag"; -const char kTestDownloadPathPrefix[] = "/download/"; class GDataWapiRequestsTest : public testing::Test { public: - GDataWapiRequestsTest() { - } - virtual void SetUp() OVERRIDE { request_context_getter_ = new net::TestURLRequestContextGetter( message_loop_.message_loop_proxy()); @@ -51,35 +36,13 @@ class GDataWapiRequestsTest : public testing::Test { message_loop_.message_loop_proxy(), kTestUserAgent)); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady()); test_server_.RegisterRequestHandler( - base::Bind(&test_util::HandleDownloadFileRequest, - test_server_.base_url(), - base::Unretained(&http_request_))); - test_server_.RegisterRequestHandler( base::Bind(&GDataWapiRequestsTest::HandleResourceFeedRequest, base::Unretained(this))); - test_server_.RegisterRequestHandler( - base::Bind(&GDataWapiRequestsTest::HandleMetadataRequest, - base::Unretained(this))); - test_server_.RegisterRequestHandler( - base::Bind(&GDataWapiRequestsTest::HandleCreateSessionRequest, - base::Unretained(this))); - test_server_.RegisterRequestHandler( - base::Bind(&GDataWapiRequestsTest::HandleUploadRequest, - base::Unretained(this))); - test_server_.RegisterRequestHandler( - base::Bind(&GDataWapiRequestsTest::HandleDownloadRequest, - base::Unretained(this))); GURL test_base_url = test_util::GetBaseUrlForTesting(test_server_.port()); - url_generator_.reset(new GDataWapiUrlGenerator( - test_base_url, test_base_url.Resolve(kTestDownloadPathPrefix))); - - received_bytes_ = 0; - content_length_ = 0; + url_generator_.reset(new GDataWapiUrlGenerator(test_base_url)); } protected: @@ -90,16 +53,6 @@ class GDataWapiRequestsTest : public testing::Test { const GURL absolute_url = test_server_.GetURL(request.relative_url); std::string remaining_path; - if (absolute_url.path() == "/feeds/default/private/full" && - request.method == net::test_server::METHOD_POST) { - // This is a request for copying a document. - // TODO(satorux): we should generate valid JSON data for the newly - // copied document but for now, just return "file_entry.json" - scoped_ptr<net::test_server::BasicHttpResponse> result( - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath("gdata/file_entry.json"))); - return result.PassAs<net::test_server::HttpResponse>(); - } if (!test_util::RemovePrefix(absolute_url.path(), "/feeds/default/private/full", @@ -107,236 +60,34 @@ class GDataWapiRequestsTest : public testing::Test { return scoped_ptr<net::test_server::HttpResponse>(); } - if (remaining_path.empty()) { - // Process the default feed. + // Process a feed for a single resource ID. + const std::string resource_id = net::UnescapeURLComponent( + remaining_path.substr(1), net::UnescapeRule::URL_SPECIAL_CHARS); + if (resource_id == "file:2_file_resource_id") { scoped_ptr<net::test_server::BasicHttpResponse> result( test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath("gdata/root_feed.json"))); + test_util::GetTestFilePath("gdata/file_entry.json"))); return result.PassAs<net::test_server::HttpResponse>(); - } else { - // Process a feed for a single resource ID. - const std::string resource_id = net::UnescapeURLComponent( - remaining_path.substr(1), net::UnescapeRule::URL_SPECIAL_CHARS); - if (resource_id == "file:2_file_resource_id") { - scoped_ptr<net::test_server::BasicHttpResponse> result( - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath("gdata/file_entry.json"))); - return result.PassAs<net::test_server::HttpResponse>(); - } else if (resource_id == "folder:root/contents" && - request.method == net::test_server::METHOD_POST) { - // This is a request for creating a directory in the root directory. - // TODO(satorux): we should generate valid JSON data for the newly - // created directory but for now, just return "directory_entry.json" - scoped_ptr<net::test_server::BasicHttpResponse> result( - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath( - "gdata/directory_entry.json"))); - return result.PassAs<net::test_server::HttpResponse>(); - } else if (resource_id == - "folder:root/contents/file:2_file_resource_id" && - request.method == net::test_server::METHOD_DELETE) { - // This is a request for deleting a file from the root directory. - // TODO(satorux): Investigate what's returned from the server, and - // copy it. For now, just return a random file, as the contents don't - // matter. + } else if (resource_id == "invalid_resource_id") { + // Check if this is an authorization request for an app. + // This emulates to return invalid formatted result from the server. + if (request.method == net::test_server::METHOD_PUT && + request.content.find("<docs:authorizedApp>") != std::string::npos) { scoped_ptr<net::test_server::BasicHttpResponse> result( test_util::CreateHttpResponseFromFile( test_util::GetTestFilePath("gdata/testfile.txt"))); return result.PassAs<net::test_server::HttpResponse>(); - } else if (resource_id == "invalid_resource_id") { - // Check if this is an authorization request for an app. - // This emulates to return invalid formatted result from the server. - if (request.method == net::test_server::METHOD_PUT && - request.content.find("<docs:authorizedApp>") != std::string::npos) { - scoped_ptr<net::test_server::BasicHttpResponse> result( - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath("gdata/testfile.txt"))); - return result.PassAs<net::test_server::HttpResponse>(); - } - } - } - - return scoped_ptr<net::test_server::HttpResponse>(); - } - - // Handles a request for fetching a metadata feed. - scoped_ptr<net::test_server::HttpResponse> HandleMetadataRequest( - const net::test_server::HttpRequest& request) { - http_request_ = request; - - const GURL absolute_url = test_server_.GetURL(request.relative_url); - if (absolute_url.path() != "/feeds/metadata/default") - return scoped_ptr<net::test_server::HttpResponse>(); - - scoped_ptr<net::test_server::BasicHttpResponse> result( - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath( - "gdata/account_metadata.json"))); - if (absolute_url.query().find("include-installed-apps=true") == - string::npos) { - // Exclude the list of installed apps. - scoped_ptr<base::Value> parsed_content( - base::JSONReader::Read(result->content(), base::JSON_PARSE_RFC)); - CHECK(parsed_content); - - // Remove the install apps node. - base::DictionaryValue* dictionary_value; - CHECK(parsed_content->GetAsDictionary(&dictionary_value)); - dictionary_value->Remove("entry.docs$installedApp", NULL); - - // Write back it as the content of the result. - std::string content; - base::JSONWriter::Write(parsed_content.get(), &content); - result->set_content(content); - } - - return result.PassAs<net::test_server::HttpResponse>(); - } - - // Handles a request for creating a session for uploading. - scoped_ptr<net::test_server::HttpResponse> HandleCreateSessionRequest( - const net::test_server::HttpRequest& request) { - http_request_ = request; - - const GURL absolute_url = test_server_.GetURL(request.relative_url); - if (StartsWithASCII(absolute_url.path(), - "/feeds/upload/create-session/default/private/full", - true)) { // case sensitive - // This is an initiating upload URL. - scoped_ptr<net::test_server::BasicHttpResponse> http_response( - new net::test_server::BasicHttpResponse); - - // Check an ETag. - std::map<std::string, std::string>::const_iterator found = - request.headers.find("If-Match"); - if (found != request.headers.end() && - found->second != "*" && - found->second != kTestETag) { - http_response->set_code(net::HTTP_PRECONDITION_FAILED); - return http_response.PassAs<net::test_server::HttpResponse>(); - } - - // Check if the X-Upload-Content-Length is present. If yes, store the - // length of the file. - found = request.headers.find("X-Upload-Content-Length"); - if (found == request.headers.end() || - !base::StringToInt64(found->second, &content_length_)) { - return scoped_ptr<net::test_server::HttpResponse>(); - } - received_bytes_ = 0; - - http_response->set_code(net::HTTP_OK); - GURL upload_url; - // POST is used for a new file, and PUT is used for an existing file. - if (request.method == net::test_server::METHOD_POST) { - upload_url = test_server_.GetURL("/upload_new_file"); - } else if (request.method == net::test_server::METHOD_PUT) { - upload_url = test_server_.GetURL("/upload_existing_file"); - } else { - return scoped_ptr<net::test_server::HttpResponse>(); } - http_response->AddCustomHeader("Location", upload_url.spec()); - return http_response.PassAs<net::test_server::HttpResponse>(); } return scoped_ptr<net::test_server::HttpResponse>(); } - // Handles a request for uploading content. - scoped_ptr<net::test_server::HttpResponse> HandleUploadRequest( - const net::test_server::HttpRequest& request) { - http_request_ = request; - - const GURL absolute_url = test_server_.GetURL(request.relative_url); - if (absolute_url.path() != "/upload_new_file" && - absolute_url.path() != "/upload_existing_file") { - return scoped_ptr<net::test_server::HttpResponse>(); - } - - // TODO(satorux): We should create a correct JSON data for the uploaded - // file, but for now, just return file_entry.json. - scoped_ptr<net::test_server::BasicHttpResponse> response = - test_util::CreateHttpResponseFromFile( - test_util::GetTestFilePath("gdata/file_entry.json")); - // response.code() is set to SUCCESS. Change it to CREATED if it's a new - // file. - if (absolute_url.path() == "/upload_new_file") - response->set_code(net::HTTP_CREATED); - - // Check if the Content-Range header is present. This must be present if - // the request body is not empty. - if (!request.content.empty()) { - std::map<std::string, std::string>::const_iterator iter = - request.headers.find("Content-Range"); - if (iter == request.headers.end()) - return scoped_ptr<net::test_server::HttpResponse>(); - int64 length = 0; - int64 start_position = 0; - int64 end_position = 0; - if (!test_util::ParseContentRangeHeader(iter->second, - &start_position, - &end_position, - &length)) { - return scoped_ptr<net::test_server::HttpResponse>(); - } - EXPECT_EQ(start_position, received_bytes_); - EXPECT_EQ(length, content_length_); - // end_position is inclusive, but so +1 to change the range to byte size. - received_bytes_ = end_position + 1; - } - - // Add Range header to the response, based on the values of - // Content-Range header in the request. - // The header is annotated only when at least one byte is received. - if (received_bytes_ > 0) { - response->AddCustomHeader( - "Range", - "bytes=0-" + base::Int64ToString(received_bytes_ - 1)); - } - - // Change the code to RESUME_INCOMPLETE if upload is not complete. - if (received_bytes_ < content_length_) - response->set_code(static_cast<net::HttpStatusCode>(308)); - - return response.PassAs<net::test_server::HttpResponse>(); - } - - // Handles a request for downloading a file. - scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest( - const net::test_server::HttpRequest& request) { - http_request_ = request; - - const GURL absolute_url = test_server_.GetURL(request.relative_url); - std::string id; - if (!test_util::RemovePrefix(absolute_url.path(), - kTestDownloadPathPrefix, - &id)) { - return scoped_ptr<net::test_server::HttpResponse>(); - } - - // For testing, returns a text with |id| repeated 3 times. - scoped_ptr<net::test_server::BasicHttpResponse> response( - new net::test_server::BasicHttpResponse); - response->set_code(net::HTTP_OK); - response->set_content(id + id + id); - response->set_content_type("text/plain"); - return response.PassAs<net::test_server::HttpResponse>(); - } - base::MessageLoopForIO message_loop_; // Test server needs IO thread. net::test_server::EmbeddedTestServer test_server_; scoped_ptr<RequestSender> request_sender_; scoped_ptr<GDataWapiUrlGenerator> url_generator_; scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; - base::ScopedTempDir temp_dir_; - - // These fields are used to keep the current upload state during a - // test case. These values are updated by the request from - // ResumeUploadRequest, and used to construct the response for - // both ResumeUploadRequest and GetUploadStatusRequest, to emulate - // the WAPI server. - int64 received_bytes_; - int64 content_length_; // The incoming HTTP request is saved so tests can verify the request // parameters like HTTP method (ex. some requests should use DELETE @@ -346,130 +97,6 @@ class GDataWapiRequestsTest : public testing::Test { } // namespace -TEST_F(GDataWapiRequestsTest, GetResourceListRequest_DefaultFeed) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<ResourceList> result_data; - - { - base::RunLoop run_loop; - GetResourceListRequest* request = new GetResourceListRequest( - request_sender_.get(), - *url_generator_, - GURL(), // Pass an empty URL to use the default feed - 0, // start changestamp - std::string(), // search string - std::string(), // directory resource ID - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data))); - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&" - "showfolders=true&include-shared=true&max-results=500", - http_request_.relative_url); - - // Sanity check of the result. - scoped_ptr<ResourceList> expected( - ResourceList::ExtractAndParse( - *test_util::LoadJSONFile("gdata/root_feed.json"))); - ASSERT_TRUE(result_data); - EXPECT_EQ(expected->title(), result_data->title()); -} - -TEST_F(GDataWapiRequestsTest, GetResourceListRequest_ValidFeed) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<ResourceList> result_data; - - { - base::RunLoop run_loop; - GetResourceListRequest* request = new GetResourceListRequest( - request_sender_.get(), - *url_generator_, - test_server_.GetURL("/files/gdata/root_feed.json"), - 0, // start changestamp - std::string(), // search string - std::string(), // directory resource ID - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data))); - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/files/gdata/root_feed.json?v=3&alt=json&showroot=true&" - "showfolders=true&include-shared=true&max-results=500", - http_request_.relative_url); - - scoped_ptr<ResourceList> expected( - ResourceList::ExtractAndParse( - *test_util::LoadJSONFile("gdata/root_feed.json"))); - ASSERT_TRUE(result_data); - EXPECT_EQ(expected->title(), result_data->title()); -} - -TEST_F(GDataWapiRequestsTest, GetResourceListRequest_InvalidFeed) { - // testfile.txt exists but the response is not JSON, so it should - // emit a parse error instead. - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<ResourceList> result_data; - - { - base::RunLoop run_loop; - GetResourceListRequest* request = new GetResourceListRequest( - request_sender_.get(), - *url_generator_, - test_server_.GetURL("/files/gdata/testfile.txt"), - 0, // start changestamp - std::string(), // search string - std::string(), // directory resource ID - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data))); - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(GDATA_PARSE_ERROR, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/files/gdata/testfile.txt?v=3&alt=json&showroot=true&" - "showfolders=true&include-shared=true&max-results=500", - http_request_.relative_url); - EXPECT_FALSE(result_data); -} - -TEST_F(GDataWapiRequestsTest, SearchByTitleRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<ResourceList> result_data; - - { - base::RunLoop run_loop; - SearchByTitleRequest* request = new SearchByTitleRequest( - request_sender_.get(), - *url_generator_, - "search-title", - std::string(), // directory resource id - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data))); - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&" - "showfolders=true&include-shared=true&max-results=500" - "&title=search-title&title-exact=true", - http_request_.relative_url); - EXPECT_TRUE(result_data); -} - TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) { GDataErrorCode result_code = GDATA_OTHER_ERROR; scoped_ptr<base::Value> result_data; @@ -526,1036 +153,4 @@ TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_InvalidResourceId) { ASSERT_FALSE(result_data); } -TEST_F(GDataWapiRequestsTest, GetAccountMetadataRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<AccountMetadata> result_data; - - { - base::RunLoop run_loop; - GetAccountMetadataRequest* request = new GetAccountMetadataRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - true); // Include installed apps. - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true" - "&include-installed-apps=true", - http_request_.relative_url); - - scoped_ptr<AccountMetadata> expected( - AccountMetadata::CreateFrom( - *test_util::LoadJSONFile("gdata/account_metadata.json"))); - - ASSERT_TRUE(result_data.get()); - EXPECT_EQ(expected->largest_changestamp(), - result_data->largest_changestamp()); - EXPECT_EQ(expected->quota_bytes_total(), - result_data->quota_bytes_total()); - EXPECT_EQ(expected->quota_bytes_used(), - result_data->quota_bytes_used()); - - // Sanity check for installed apps. - EXPECT_EQ(expected->installed_apps().size(), - result_data->installed_apps().size()); -} - -TEST_F(GDataWapiRequestsTest, - GetAccountMetadataRequestWithoutInstalledApps) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<AccountMetadata> result_data; - - { - base::RunLoop run_loop; - GetAccountMetadataRequest* request = new GetAccountMetadataRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - false); // Exclude installed apps. - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true", - http_request_.relative_url); - - scoped_ptr<AccountMetadata> expected( - AccountMetadata::CreateFrom( - *test_util::LoadJSONFile("gdata/account_metadata.json"))); - - ASSERT_TRUE(result_data.get()); - EXPECT_EQ(expected->largest_changestamp(), - result_data->largest_changestamp()); - EXPECT_EQ(expected->quota_bytes_total(), - result_data->quota_bytes_total()); - EXPECT_EQ(expected->quota_bytes_used(), - result_data->quota_bytes_used()); - - // Installed apps shouldn't be included. - EXPECT_EQ(0U, result_data->installed_apps().size()); -} - -TEST_F(GDataWapiRequestsTest, DeleteResourceRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - - { - base::RunLoop run_loop; - DeleteResourceRequest* request = new DeleteResourceRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code)), - "file:2_file_resource_id", - std::string()); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method); - EXPECT_EQ( - "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json" - "&showroot=true", - http_request_.relative_url); - EXPECT_EQ("*", http_request_.headers["If-Match"]); -} - -TEST_F(GDataWapiRequestsTest, DeleteResourceRequestWithETag) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - - { - base::RunLoop run_loop; - DeleteResourceRequest* request = new DeleteResourceRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code)), - "file:2_file_resource_id", - "etag"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method); - EXPECT_EQ( - "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json" - "&showroot=true", - http_request_.relative_url); - EXPECT_EQ("etag", http_request_.headers["If-Match"]); -} - -TEST_F(GDataWapiRequestsTest, CreateDirectoryRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - scoped_ptr<base::Value> result_data; - - // Create "new directory" in the root directory. - { - base::RunLoop run_loop; - CreateDirectoryRequest* request = new CreateDirectoryRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - "folder:root", - "new directory"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json" - "&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n" - " <category scheme=\"http://schemas.google.com/g/2005#kind\" " - "term=\"http://schemas.google.com/docs/2007#folder\"/>\n" - " <title>new directory</title>\n" - "</entry>\n", - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, RenameResourceRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - - // Rename a file with a new name "New File". - { - base::RunLoop run_loop; - RenameResourceRequest* request = new RenameResourceRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code)), - "file:2_file_resource_id", - "New File"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - EXPECT_EQ( - "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json" - "&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n" - " <title>New File</title>\n" - "</entry>\n", - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_ValidFeed) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL result_data; - - // Authorize an app with APP_ID to access to a document. - { - base::RunLoop run_loop; - AuthorizeAppRequest* request = new AuthorizeAppRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - "file:2_file_resource_id", - "the_app_id"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(GURL("https://entry1_open_with_link/"), result_data); - - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id" - "?v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <docs:authorizedApp>the_app_id</docs:authorizedApp>\n" - "</entry>\n", - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_NotFound) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL result_data; - - // Authorize an app with APP_ID to access to a document. - { - base::RunLoop run_loop; - AuthorizeAppRequest* request = new AuthorizeAppRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - "file:2_file_resource_id", - "unauthorized_app_id"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(GDATA_OTHER_ERROR, result_code); - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id" - "?v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <docs:authorizedApp>unauthorized_app_id</docs:authorizedApp>\n" - "</entry>\n", - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_InvalidFeed) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL result_data; - - // Authorize an app with APP_ID to access to a document but an invalid feed. - { - base::RunLoop run_loop; - AuthorizeAppRequest* request = new AuthorizeAppRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &result_data)), - "invalid_resource_id", - "APP_ID"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(GDATA_PARSE_ERROR, result_code); - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/invalid_resource_id" - "?v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <docs:authorizedApp>APP_ID</docs:authorizedApp>\n" - "</entry>\n", - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, AddResourceToDirectoryRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - - // Add a file to the root directory. - { - base::RunLoop run_loop; - AddResourceToDirectoryRequest* request = - new AddResourceToDirectoryRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code)), - "folder:root", - "file:2_file_resource_id"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json" - "&showroot=true", - http_request_.relative_url); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(base::StringPrintf("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n" - " <id>%sfeeds/default/private/full/" - "file%%3A2_file_resource_id</id>\n" - "</entry>\n", - test_server_.base_url().spec().c_str()), - http_request_.content); -} - -TEST_F(GDataWapiRequestsTest, RemoveResourceFromDirectoryRequest) { - GDataErrorCode result_code = GDATA_OTHER_ERROR; - - // Remove a file from the root directory. - { - base::RunLoop run_loop; - RemoveResourceFromDirectoryRequest* request = - new RemoveResourceFromDirectoryRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code)), - "folder:root", - "file:2_file_resource_id"); - - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - // DELETE method should be used, without the body content. - EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method); - EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents/" - "file%3A2_file_resource_id?v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - EXPECT_FALSE(http_request_.has_content); -} - -// This test exercises InitiateUploadNewFileRequest and -// ResumeUploadRequest for a scenario of uploading a new file. -TEST_F(GDataWapiRequestsTest, UploadNewFile) { - const std::string kUploadContent = "hello"; - const base::FilePath kTestFilePath = - temp_dir_.path().AppendASCII("upload_file.txt"); - ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent)); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - // 1) Get the upload URL for uploading a new file. - { - base::RunLoop run_loop; - InitiateUploadNewFileRequest* initiate_request = - new InitiateUploadNewFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "folder:id", - "New file"); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url); - EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ( - "/feeds/upload/create-session/default/private/full/folder%3Aid/contents" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <title>New file</title>\n" - "</entry>\n", - http_request_.content); - - // 2) Upload the content to the upload URL. - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - { - base::RunLoop run_loop; - ResumeUploadRequest* resume_request = new ResumeUploadRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - ProgressCallback(), - upload_url, - 0, // start_position - kUploadContent.size(), // end_position (exclusive) - kUploadContent.size(), // content_length, - "text/plain", // content_type - kTestFilePath); - - request_sender_->StartRequestWithRetry(resume_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes 0-" + - base::Int64ToString(kUploadContent.size() -1) + "/" + - base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - // The upload content should be set in the HTTP request. - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(kUploadContent, http_request_.content); - - // Check the response. - EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file - // The start and end positions should be set to -1, if an upload is complete. - EXPECT_EQ(-1, response.start_position_received); - EXPECT_EQ(-1, response.end_position_received); -} - -// This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest -// for a scenario of uploading a new *large* file, which requires multiple -// requests of ResumeUploadRequest. GetUploadRequest is also tested in this -// test case. -TEST_F(GDataWapiRequestsTest, UploadNewLargeFile) { - const size_t kMaxNumBytes = 10; - // This is big enough to cause multiple requests of ResumeUploadRequest - // as we are going to send at most kMaxNumBytes at a time. - // So, sending "kMaxNumBytes * 2 + 1" bytes ensures three - // ResumeUploadRequests, which are start, middle and last requests. - const std::string kUploadContent(kMaxNumBytes * 2 + 1, 'a'); - const base::FilePath kTestFilePath = - temp_dir_.path().AppendASCII("upload_file.txt"); - ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent)); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - // 1) Get the upload URL for uploading a new file. - { - base::RunLoop run_loop; - InitiateUploadNewFileRequest* initiate_request = - new InitiateUploadNewFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "folder:id", - "New file"); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url); - EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ( - "/feeds/upload/create-session/default/private/full/folder%3Aid/contents" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <title>New file</title>\n" - "</entry>\n", - http_request_.content); - - // 2) Before sending any data, check the current status. - // This is an edge case test for GetUploadStatusRequest - // (UploadRangeRequestBase). - { - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - // Check the response by GetUploadStatusRequest. - { - base::RunLoop run_loop; - GetUploadStatusRequest* get_upload_status_request = - new GetUploadStatusRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - upload_url, - kUploadContent.size()); - request_sender_->StartRequestWithRetry(get_upload_status_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - EXPECT_TRUE(http_request_.has_content); - EXPECT_TRUE(http_request_.content.empty()); - - // Check the response. - EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code); - EXPECT_EQ(0, response.start_position_received); - EXPECT_EQ(0, response.end_position_received); - } - - // 3) Upload the content to the upload URL with multiple requests. - size_t num_bytes_consumed = 0; - for (size_t start_position = 0; start_position < kUploadContent.size(); - start_position += kMaxNumBytes) { - SCOPED_TRACE(testing::Message("start_position: ") << start_position); - - // The payload is at most kMaxNumBytes. - const size_t remaining_size = kUploadContent.size() - start_position; - const std::string payload = kUploadContent.substr( - start_position, std::min(kMaxNumBytes, remaining_size)); - num_bytes_consumed += payload.size(); - // The end position is exclusive. - const size_t end_position = start_position + payload.size(); - - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - { - base::RunLoop run_loop; - ResumeUploadRequest* resume_request = new ResumeUploadRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - ProgressCallback(), - upload_url, - start_position, - end_position, - kUploadContent.size(), // content_length, - "text/plain", // content_type - kTestFilePath); - request_sender_->StartRequestWithRetry(resume_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes " + - base::Int64ToString(start_position) + "-" + - base::Int64ToString(end_position - 1) + "/" + - base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - // The upload content should be set in the HTTP request. - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(payload, http_request_.content); - - // Check the response. - if (payload.size() == remaining_size) { - EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file. - // The start and end positions should be set to -1, if an upload is - // complete. - EXPECT_EQ(-1, response.start_position_received); - EXPECT_EQ(-1, response.end_position_received); - // The upload process is completed, so exit from the loop. - break; - } - - EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code); - EXPECT_EQ(0, response.start_position_received); - EXPECT_EQ(static_cast<int64>(end_position), - response.end_position_received); - - // Check the response by GetUploadStatusRequest. - { - base::RunLoop run_loop; - GetUploadStatusRequest* get_upload_status_request = - new GetUploadStatusRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - upload_url, - kUploadContent.size()); - request_sender_->StartRequestWithRetry(get_upload_status_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - EXPECT_TRUE(http_request_.has_content); - EXPECT_TRUE(http_request_.content.empty()); - - // Check the response. - EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code); - EXPECT_EQ(0, response.start_position_received); - EXPECT_EQ(static_cast<int64>(end_position), - response.end_position_received); - } - - EXPECT_EQ(kUploadContent.size(), num_bytes_consumed); -} - -// This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest -// for a scenario of uploading a new *empty* file. -// -// The test is almost identical to UploadNewFile. The only difference is the -// expectation for the Content-Range header. -TEST_F(GDataWapiRequestsTest, UploadNewEmptyFile) { - const std::string kUploadContent; - const base::FilePath kTestFilePath = - temp_dir_.path().AppendASCII("empty_file.txt"); - ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent)); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - // 1) Get the upload URL for uploading a new file. - { - base::RunLoop run_loop; - InitiateUploadNewFileRequest* initiate_request = - new InitiateUploadNewFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "folder:id", - "New file"); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url); - EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ( - "/feeds/upload/create-session/default/private/full/folder%3Aid/contents" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("<?xml version=\"1.0\"?>\n" - "<entry xmlns=\"http://www.w3.org/2005/Atom\" " - "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" - " <title>New file</title>\n" - "</entry>\n", - http_request_.content); - - // 2) Upload the content to the upload URL. - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - { - base::RunLoop run_loop; - ResumeUploadRequest* resume_request = new ResumeUploadRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - ProgressCallback(), - upload_url, - 0, // start_position - kUploadContent.size(), // end_position (exclusive) - kUploadContent.size(), // content_length, - "text/plain", // content_type - kTestFilePath); - request_sender_->StartRequestWithRetry(resume_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should not exit if the content is empty. - // We should not generate the header with an invalid value "bytes 0--1/0". - EXPECT_EQ(0U, http_request_.headers.count("Content-Range")); - // The upload content should be set in the HTTP request. - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(kUploadContent, http_request_.content); - - // Check the response. - EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file. - // The start and end positions should be set to -1, if an upload is complete. - EXPECT_EQ(-1, response.start_position_received); - EXPECT_EQ(-1, response.end_position_received); -} - -// This test exercises InitiateUploadExistingFileRequest and -// ResumeUploadRequest for a scenario of updating an existing file. -TEST_F(GDataWapiRequestsTest, UploadExistingFile) { - const std::string kUploadContent = "hello"; - const base::FilePath kTestFilePath = - temp_dir_.path().AppendASCII("upload_file.txt"); - ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent)); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - // 1) Get the upload URL for uploading an existing file. - { - base::RunLoop run_loop; - InitiateUploadExistingFileRequest* initiate_request = - new InitiateUploadExistingFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "file:foo", - std::string() /* etag */); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url); - // For updating an existing file, METHOD_PUT should be used. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - // Even though the body is empty, the content type should be set to - // "text/plain". - EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - // For updating an existing file, an empty body should be attached (PUT - // requires a body) - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("", http_request_.content); - EXPECT_EQ("*", http_request_.headers["If-Match"]); - - // 2) Upload the content to the upload URL. - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - { - base::RunLoop run_loop; - ResumeUploadRequest* resume_request = new ResumeUploadRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - ProgressCallback(), - upload_url, - 0, // start_position - kUploadContent.size(), // end_position (exclusive) - kUploadContent.size(), // content_length, - "text/plain", // content_type - kTestFilePath); - - request_sender_->StartRequestWithRetry(resume_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes 0-" + - base::Int64ToString(kUploadContent.size() -1) + "/" + - base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - // The upload content should be set in the HTTP request. - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(kUploadContent, http_request_.content); - - // Check the response. - EXPECT_EQ(HTTP_SUCCESS, response.code); // Because it's an existing file. - // The start and end positions should be set to -1, if an upload is complete. - EXPECT_EQ(-1, response.start_position_received); - EXPECT_EQ(-1, response.end_position_received); -} - -// This test exercises InitiateUploadExistingFileRequest and -// ResumeUploadRequest for a scenario of updating an existing file. -TEST_F(GDataWapiRequestsTest, UploadExistingFileWithETag) { - const std::string kUploadContent = "hello"; - const base::FilePath kTestFilePath = - temp_dir_.path().AppendASCII("upload_file.txt"); - ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent)); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - // 1) Get the upload URL for uploading an existing file. - { - base::RunLoop run_loop; - InitiateUploadExistingFileRequest* initiate_request = - new InitiateUploadExistingFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "file:foo", - kTestETag); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url); - // For updating an existing file, METHOD_PUT should be used. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - // Even though the body is empty, the content type should be set to - // "text/plain". - EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - // For updating an existing file, an empty body should be attached (PUT - // requires a body) - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("", http_request_.content); - EXPECT_EQ(kTestETag, http_request_.headers["If-Match"]); - - // 2) Upload the content to the upload URL. - UploadRangeResponse response; - scoped_ptr<ResourceEntry> new_entry; - - { - base::RunLoop run_loop; - ResumeUploadRequest* resume_request = new ResumeUploadRequest( - request_sender_.get(), - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&response, &new_entry)), - ProgressCallback(), - upload_url, - 0, // start_position - kUploadContent.size(), // end_position (exclusive) - kUploadContent.size(), // content_length, - "text/plain", // content_type - kTestFilePath); - request_sender_->StartRequestWithRetry(resume_request); - run_loop.Run(); - } - - // METHOD_PUT should be used to upload data. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // Request should go to the upload URL. - EXPECT_EQ(upload_url.path(), http_request_.relative_url); - // Content-Range header should be added. - EXPECT_EQ("bytes 0-" + - base::Int64ToString(kUploadContent.size() -1) + "/" + - base::Int64ToString(kUploadContent.size()), - http_request_.headers["Content-Range"]); - // The upload content should be set in the HTTP request. - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ(kUploadContent, http_request_.content); - - // Check the response. - EXPECT_EQ(HTTP_SUCCESS, response.code); // Because it's an existing file. - // The start and end positions should be set to -1, if an upload is complete. - EXPECT_EQ(-1, response.start_position_received); - EXPECT_EQ(-1, response.end_position_received); -} - -// This test exercises InitiateUploadExistingFileRequest for a scenario of -// confliction on updating an existing file. -TEST_F(GDataWapiRequestsTest, UploadExistingFileWithETagConflict) { - const std::string kUploadContent = "hello"; - const std::string kWrongETag = "wrong_etag"; - GDataErrorCode result_code = GDATA_OTHER_ERROR; - GURL upload_url; - - { - base::RunLoop run_loop; - InitiateUploadExistingFileRequest* initiate_request = - new InitiateUploadExistingFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &upload_url)), - "text/plain", - kUploadContent.size(), - "file:foo", - kWrongETag); - request_sender_->StartRequestWithRetry(initiate_request); - run_loop.Run(); - } - - EXPECT_EQ(HTTP_PRECONDITION, result_code); - // For updating an existing file, METHOD_PUT should be used. - EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method); - // convert=false should be passed as files should be uploaded as-is. - EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo" - "?convert=false&v=3&alt=json&showroot=true", - http_request_.relative_url); - // Even though the body is empty, the content type should be set to - // "text/plain". - EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]); - EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); - EXPECT_EQ(base::Int64ToString(kUploadContent.size()), - http_request_.headers["X-Upload-Content-Length"]); - // For updating an existing file, an empty body should be attached (PUT - // requires a body) - EXPECT_TRUE(http_request_.has_content); - EXPECT_EQ("", http_request_.content); - EXPECT_EQ(kWrongETag, http_request_.headers["If-Match"]); -} - -TEST_F(GDataWapiRequestsTest, DownloadFileRequest) { - const base::FilePath kDownloadedFilePath = - temp_dir_.path().AppendASCII("cache_file"); - const std::string kTestIdWithTypeLabel("file:dummyId"); - const std::string kTestId("dummyId"); - - GDataErrorCode result_code = GDATA_OTHER_ERROR; - base::FilePath temp_file; - { - base::RunLoop run_loop; - DownloadFileRequest* request = new DownloadFileRequest( - request_sender_.get(), - *url_generator_, - test_util::CreateQuitCallback( - &run_loop, - test_util::CreateCopyResultCallback(&result_code, &temp_file)), - GetContentCallback(), - ProgressCallback(), - kTestIdWithTypeLabel, - kDownloadedFilePath); - request_sender_->StartRequestWithRetry(request); - run_loop.Run(); - } - - std::string contents; - base::ReadFileToString(temp_file, &contents); - base::DeleteFile(temp_file, false); - - EXPECT_EQ(HTTP_SUCCESS, result_code); - EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method); - EXPECT_EQ(kTestDownloadPathPrefix + kTestId, http_request_.relative_url); - EXPECT_EQ(kDownloadedFilePath, temp_file); - - const std::string expected_contents = kTestId + kTestId + kTestId; - EXPECT_EQ(expected_contents, contents); -} - } // namespace google_apis diff --git a/chromium/google_apis/drive/gdata_wapi_url_generator.cc b/chromium/google_apis/drive/gdata_wapi_url_generator.cc index c1263b71f34..ffdb0f3d943 100644 --- a/chromium/google_apis/drive/gdata_wapi_url_generator.cc +++ b/chromium/google_apis/drive/gdata_wapi_url_generator.cc @@ -14,52 +14,15 @@ namespace google_apis { namespace { -// Content URL for modification or resource list retrieval in a particular -// directory specified by "%s" which will be replaced with its resource id. -const char kContentURLFormat[] = "/feeds/default/private/full/%s/contents"; - -// Content URL for removing a resource specified by the latter "%s" from the -// directory specified by the former "%s". -const char kResourceURLForRemovalFormat[] = - "/feeds/default/private/full/%s/contents/%s"; - // URL requesting single resource entry whose resource id is followed by this // prefix. const char kGetEditURLPrefix[] = "/feeds/default/private/full/"; -// Root resource list url. -const char kResourceListRootURL[] = "/feeds/default/private/full"; - -// Metadata feed with things like user quota. -const char kAccountMetadataURL[] = "/feeds/metadata/default"; - -// URL to upload a new file under a particular directory specified by "%s". -const char kInitiateUploadNewFileURLFormat[] = - "/feeds/upload/create-session/default/private/full/%s/contents"; - -// URL to upload a file content to overwrite a file whose resource id is -// followed by this prefix. -const char kInitiateUploadExistingFileURLPrefix[] = - "/feeds/upload/create-session/default/private/full/"; - -// Maximum number of resource entries to include in a feed. -// Be careful not to use something too small because it might overload the -// server. Be careful not to use something too large because it makes the -// "fetched N items" UI less responsive. -const int kMaxDocumentsPerFeed = 500; -const int kMaxDocumentsPerSearchFeed = 50; - -// URL requesting documents list of changes to documents collections. -const char kGetChangesListURL[] = "/feeds/default/private/changes"; - } // namespace const char GDataWapiUrlGenerator::kBaseUrlForProduction[] = "https://docs.google.com/"; -const char GDataWapiUrlGenerator::kBaseDownloadUrlForProduction[] = - "https://www.googledrive.com/host/"; - // static GURL GDataWapiUrlGenerator::AddStandardUrlParams(const GURL& url) { GURL result = net::AppendOrReplaceQueryParameter(url, "v", "3"); @@ -68,90 +31,13 @@ GURL GDataWapiUrlGenerator::AddStandardUrlParams(const GURL& url) { return result; } -// static -GURL GDataWapiUrlGenerator::AddInitiateUploadUrlParams(const GURL& url) { - GURL result = net::AppendOrReplaceQueryParameter(url, "convert", "false"); - return AddStandardUrlParams(result); -} - -// static -GURL GDataWapiUrlGenerator::AddFeedUrlParams( - const GURL& url, - int num_items_to_fetch) { - GURL result = AddStandardUrlParams(url); - result = net::AppendOrReplaceQueryParameter(result, "showfolders", "true"); - result = net::AppendOrReplaceQueryParameter(result, "include-shared", "true"); - result = net::AppendOrReplaceQueryParameter( - result, "max-results", base::IntToString(num_items_to_fetch)); - return result; -} - -GDataWapiUrlGenerator::GDataWapiUrlGenerator(const GURL& base_url, - const GURL& base_download_url) - : base_url_(base_url), - base_download_url_(base_download_url) { +GDataWapiUrlGenerator::GDataWapiUrlGenerator(const GURL& base_url) + : base_url_(base_url) { } GDataWapiUrlGenerator::~GDataWapiUrlGenerator() { } -GURL GDataWapiUrlGenerator::GenerateResourceListUrl( - const GURL& override_url, - int64 start_changestamp, - const std::string& search_string, - const std::string& directory_resource_id) const { - DCHECK_LE(0, start_changestamp); - - int max_docs = search_string.empty() ? kMaxDocumentsPerFeed : - kMaxDocumentsPerSearchFeed; - GURL url; - if (!override_url.is_empty()) { - // |override_url| specifies the URL of the continuation feed when the feed - // is broken up to multiple chunks. In this case we must not add the - // |start_changestamp| that provides the original start point. - start_changestamp = 0; - url = override_url; - } else if (start_changestamp > 0) { - // The start changestamp shouldn't be used for a search. - DCHECK(search_string.empty()); - url = base_url_.Resolve(kGetChangesListURL); - } else if (!directory_resource_id.empty()) { - url = base_url_.Resolve( - base::StringPrintf(kContentURLFormat, - net::EscapePath( - directory_resource_id).c_str())); - } else { - url = base_url_.Resolve(kResourceListRootURL); - } - - url = AddFeedUrlParams(url, max_docs); - - if (start_changestamp) { - url = net::AppendOrReplaceQueryParameter( - url, "start-index", base::Int64ToString(start_changestamp)); - } - if (!search_string.empty()) { - url = net::AppendOrReplaceQueryParameter(url, "q", search_string); - } - - return url; -} - -GURL GDataWapiUrlGenerator::GenerateSearchByTitleUrl( - const std::string& title, - const std::string& directory_resource_id) const { - DCHECK(!title.empty()); - - GURL url = directory_resource_id.empty() ? - base_url_.Resolve(kResourceListRootURL) : - base_url_.Resolve(base::StringPrintf( - kContentURLFormat, net::EscapePath(directory_resource_id).c_str())); - url = AddFeedUrlParams(url, kMaxDocumentsPerFeed); - url = net::AppendOrReplaceQueryParameter(url, "title", title); - url = net::AppendOrReplaceQueryParameter(url, "title-exact", "true"); - return url; -} - GURL GDataWapiUrlGenerator::GenerateEditUrl( const std::string& resource_id) const { return AddStandardUrlParams(GenerateEditUrlWithoutParams(resource_id)); @@ -180,71 +66,4 @@ GURL GDataWapiUrlGenerator::GenerateEditUrlWithEmbedOrigin( return url; } -GURL GDataWapiUrlGenerator::GenerateContentUrl( - const std::string& resource_id) const { - if (resource_id.empty()) { - // |resource_id| must not be empty. Return an empty GURL as an error. - return GURL(); - } - - GURL result = base_url_.Resolve( - base::StringPrintf(kContentURLFormat, - net::EscapePath(resource_id).c_str())); - return AddStandardUrlParams(result); -} - -GURL GDataWapiUrlGenerator::GenerateResourceUrlForRemoval( - const std::string& parent_resource_id, - const std::string& resource_id) const { - if (resource_id.empty() || parent_resource_id.empty()) { - // Both |resource_id| and |parent_resource_id| must be non-empty. - // Return an empty GURL as an error. - return GURL(); - } - - GURL result = base_url_.Resolve( - base::StringPrintf(kResourceURLForRemovalFormat, - net::EscapePath(parent_resource_id).c_str(), - net::EscapePath(resource_id).c_str())); - return AddStandardUrlParams(result); -} - -GURL GDataWapiUrlGenerator::GenerateInitiateUploadNewFileUrl( - const std::string& parent_resource_id) const { - GURL result = base_url_.Resolve( - base::StringPrintf(kInitiateUploadNewFileURLFormat, - net::EscapePath(parent_resource_id).c_str())); - return AddInitiateUploadUrlParams(result); -} - -GURL GDataWapiUrlGenerator::GenerateInitiateUploadExistingFileUrl( - const std::string& resource_id) const { - GURL result = base_url_.Resolve( - kInitiateUploadExistingFileURLPrefix + net::EscapePath(resource_id)); - return AddInitiateUploadUrlParams(result); -} - -GURL GDataWapiUrlGenerator::GenerateResourceListRootUrl() const { - return AddStandardUrlParams(base_url_.Resolve(kResourceListRootURL)); -} - -GURL GDataWapiUrlGenerator::GenerateAccountMetadataUrl( - bool include_installed_apps) const { - GURL result = AddStandardUrlParams(base_url_.Resolve(kAccountMetadataURL)); - if (include_installed_apps) { - result = net::AppendOrReplaceQueryParameter( - result, "include-installed-apps", "true"); - } - return result; -} - -GURL GDataWapiUrlGenerator::GenerateDownloadFileUrl( - const std::string& resource_id) const { - // Strip the file type prefix before the colon character. - size_t colon = resource_id.find(':'); - return base_download_url_.Resolve(net::EscapePath( - colon == std::string::npos ? resource_id - : resource_id.substr(colon + 1))); -} - } // namespace google_apis diff --git a/chromium/google_apis/drive/gdata_wapi_url_generator.h b/chromium/google_apis/drive/gdata_wapi_url_generator.h index 05b565d404b..c0486cfff14 100644 --- a/chromium/google_apis/drive/gdata_wapi_url_generator.h +++ b/chromium/google_apis/drive/gdata_wapi_url_generator.h @@ -17,8 +17,7 @@ namespace google_apis { // for production, and the local server for testing. class GDataWapiUrlGenerator { public: - // The - GDataWapiUrlGenerator(const GURL& base_url, const GURL& base_download_url); + GDataWapiUrlGenerator(const GURL& base_url); ~GDataWapiUrlGenerator(); // The base URL for communicating with the WAPI server for production. @@ -31,53 +30,6 @@ class GDataWapiUrlGenerator { // show folders in the feed are added to document feed URLs. static GURL AddStandardUrlParams(const GURL& url); - // Adds additional parameters for initiate uploading as well as standard - // url params (as AddStandardUrlParams above does). - static GURL AddInitiateUploadUrlParams(const GURL& url); - - // Adds additional parameters for API version, output content type and to - // show folders in the feed are added to document feed URLs. - static GURL AddFeedUrlParams(const GURL& url, - int num_items_to_fetch); - - // Generates a URL for getting the resource list feed. - // - // The parameters other than |search_string| are mutually exclusive. - // If |override_url| is non-empty, other parameters are ignored. Or if - // |override_url| is empty, others are not used. Besides, |search_string| - // cannot be set together with |start_changestamp|. - // - // override_url: - // By default, a hard-coded base URL of the WAPI server is used. - // The base URL can be overridden by |override_url|. - // This is used for handling continuation of feeds (2nd page and onward). - // - // start_changestamp - // If |start_changestamp| is 0, URL for a full feed is generated. - // If |start_changestamp| is non-zero, URL for a delta feed is generated. - // - // search_string - // If |search_string| is non-empty, q=... parameter is added, and - // max-results=... parameter is adjusted for a search. - // - // directory_resource_id: - // If |directory_resource_id| is non-empty, a URL for fetching documents in - // a particular directory is generated. - // - GURL GenerateResourceListUrl( - const GURL& override_url, - int64 start_changestamp, - const std::string& search_string, - const std::string& directory_resource_id) const; - - // Generates a URL for searching resources by title (exact-match). - // |directory_resource_id| is optional parameter. When it is empty - // all the existing resources are target of the search. Otherwise, - // the search target is just under the directory with it. - GURL GenerateSearchByTitleUrl( - const std::string& title, - const std::string& directory_resource_id) const; - // Generates a URL for getting or editing the resource entry of // the given resource ID. GURL GenerateEditUrl(const std::string& resource_id) const; @@ -98,41 +50,8 @@ class GDataWapiUrlGenerator { GURL GenerateEditUrlWithEmbedOrigin(const std::string& resource_id, const GURL& embed_origin) const; - // Generates a URL for editing the contents in the directory specified - // by the given resource ID. - GURL GenerateContentUrl(const std::string& resource_id) const; - - // Generates a URL to remove an entry specified by |resource_id| from - // the directory specified by the given |parent_resource_id|. - GURL GenerateResourceUrlForRemoval(const std::string& parent_resource_id, - const std::string& resource_id) const; - - // Generates a URL to initiate uploading a new file to a directory - // specified by |parent_resource_id|. - GURL GenerateInitiateUploadNewFileUrl( - const std::string& parent_resource_id) const; - - // Generates a URL to initiate uploading file content to overwrite a - // file specified by |resource_id|. - GURL GenerateInitiateUploadExistingFileUrl( - const std::string& resource_id) const; - - // Generates a URL for getting the root resource list feed. - // Used to make changes in the root directory (ex. create a directory in the - // root directory) - GURL GenerateResourceListRootUrl() const; - - // Generates a URL for getting the account metadata feed. - // If |include_installed_apps| is set to true, the response will include the - // list of installed third party applications. - GURL GenerateAccountMetadataUrl(bool include_installed_apps) const; - - // Generates a URL for downloading a file. - GURL GenerateDownloadFileUrl(const std::string& resource_id) const; - private: const GURL base_url_; - const GURL base_download_url_; }; } // namespace google_apis diff --git a/chromium/google_apis/drive/gdata_wapi_url_generator_unittest.cc b/chromium/google_apis/drive/gdata_wapi_url_generator_unittest.cc index 63db63d6e3e..0ac8508d774 100644 --- a/chromium/google_apis/drive/gdata_wapi_url_generator_unittest.cc +++ b/chromium/google_apis/drive/gdata_wapi_url_generator_unittest.cc @@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +#include "url/url_util.h" namespace google_apis { @@ -13,8 +14,7 @@ class GDataWapiUrlGeneratorTest : public testing::Test { public: GDataWapiUrlGeneratorTest() : url_generator_( - GURL(GDataWapiUrlGenerator::kBaseUrlForProduction), - GURL(GDataWapiUrlGenerator::kBaseDownloadUrlForProduction)) { + GURL(GDataWapiUrlGenerator::kBaseUrlForProduction)) { } protected: @@ -27,113 +27,6 @@ TEST_F(GDataWapiUrlGeneratorTest, AddStandardUrlParams) { GURL("http://www.example.com")).spec()); } -TEST_F(GDataWapiUrlGeneratorTest, AddInitiateUploadUrlParams) { - EXPECT_EQ("http://www.example.com/?convert=false&v=3&alt=json&showroot=true", - GDataWapiUrlGenerator::AddInitiateUploadUrlParams( - GURL("http://www.example.com")).spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, AddFeedUrlParams) { - EXPECT_EQ( - "http://www.example.com/?v=3&alt=json&showroot=true&" - "showfolders=true" - "&include-shared=true" - "&max-results=100", - GDataWapiUrlGenerator::AddFeedUrlParams(GURL("http://www.example.com"), - 100 // num_items_to_fetch - ).spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateResourceListUrl) { - // This is the very basic URL for the GetResourceList request. - EXPECT_EQ("https://docs.google.com/feeds/default/private/full" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500", - url_generator_.GenerateResourceListUrl( - GURL(), // override_url, - 0, // start_changestamp, - std::string(), // search_string, - std::string() // directory resource ID - ).spec()); - - // With an override URL provided, the base URL is changed, but the default - // parameters remain as-is. - EXPECT_EQ("http://localhost/" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500", - url_generator_.GenerateResourceListUrl( - GURL("http://localhost/"), // override_url, - 0, // start_changestamp, - std::string(), // search_string, - std::string() // directory resource ID - ).spec()); - - // With a non-zero start_changestamp provided, the base URL is changed from - // "full" to "changes", and "start-index" parameter is added. - EXPECT_EQ("https://docs.google.com/feeds/default/private/changes" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500&start-index=100", - url_generator_.GenerateResourceListUrl( - GURL(), // override_url, - 100, // start_changestamp, - std::string(), // search_string, - std::string() // directory resource ID - ).spec()); - - // With a non-empty search string provided, "max-results" value is changed, - // and "q" parameter is added. - EXPECT_EQ("https://docs.google.com/feeds/default/private/full" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=50&q=foo", - url_generator_.GenerateResourceListUrl( - GURL(), // override_url, - 0, // start_changestamp, - "foo", // search_string, - std::string() // directory resource ID - ).spec()); - - // With a non-empty directory resource ID provided, the base URL is - // changed, but the default parameters remain. - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full/XXX/contents" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500", - url_generator_.GenerateResourceListUrl(GURL(), // override_url, - 0, // start_changestamp, - std::string(), // search_string, - "XXX" // directory resource ID - ).spec()); - - // With a non-empty override_url provided, the base URL is changed, but - // the default parameters remain. Note that start-index should not be - // overridden. - EXPECT_EQ("http://example.com/" - "?start-index=123&v=3&alt=json&showroot=true&showfolders=true" - "&include-shared=true&max-results=500", - url_generator_.GenerateResourceListUrl( - GURL("http://example.com/?start-index=123"), // override_url, - 100, // start_changestamp, - std::string(), // search_string, - "XXX" // directory resource ID - ).spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateSearchByTitleUrl) { - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500&title=search-title&title-exact=true", - url_generator_.GenerateSearchByTitleUrl( - "search-title", std::string()).spec()); - - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full/XXX/contents" - "?v=3&alt=json&showroot=true&showfolders=true&include-shared=true" - "&max-results=500&title=search-title&title-exact=true", - url_generator_.GenerateSearchByTitleUrl( - "search-title", "XXX").spec()); -} - TEST_F(GDataWapiUrlGeneratorTest, GenerateEditUrl) { EXPECT_EQ( "https://docs.google.com/feeds/default/private/full/XXX?v=3&alt=json" @@ -148,6 +41,8 @@ TEST_F(GDataWapiUrlGeneratorTest, GenerateEditUrlWithoutParams) { } TEST_F(GDataWapiUrlGeneratorTest, GenerateEditUrlWithEmbedOrigin) { + url::AddStandardScheme("chrome-extension"); + EXPECT_EQ( "https://docs.google.com/feeds/default/private/full/XXX?v=3&alt=json" "&showroot=true&embedOrigin=chrome-extension%3A%2F%2Ftest", @@ -162,61 +57,4 @@ TEST_F(GDataWapiUrlGeneratorTest, GenerateEditUrlWithEmbedOrigin) { GURL()).spec()); } -TEST_F(GDataWapiUrlGeneratorTest, GenerateContentUrl) { - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full/" - "folder%3Aroot/contents?v=3&alt=json&showroot=true", - url_generator_.GenerateContentUrl("folder:root").spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateResourceUrlForRemoval) { - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full/" - "folder%3Aroot/contents/file%3AABCDE?v=3&alt=json&showroot=true", - url_generator_.GenerateResourceUrlForRemoval( - "folder:root", "file:ABCDE").spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateInitiateUploadNewFileUrl) { - EXPECT_EQ( - "https://docs.google.com/feeds/upload/create-session/default/private/" - "full/folder%3Aabcde/contents?convert=false&v=3&alt=json&showroot=true", - url_generator_.GenerateInitiateUploadNewFileUrl("folder:abcde").spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateInitiateUploadExistingFileUrl) { - EXPECT_EQ( - "https://docs.google.com/feeds/upload/create-session/default/private/" - "full/file%3Aresource_id?convert=false&v=3&alt=json&showroot=true", - url_generator_.GenerateInitiateUploadExistingFileUrl( - "file:resource_id").spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateResourceListRootUrl) { - EXPECT_EQ( - "https://docs.google.com/feeds/default/private/full?v=3&alt=json" - "&showroot=true", - url_generator_.GenerateResourceListRootUrl().spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateAccountMetadataUrl) { - // Include installed apps. - EXPECT_EQ( - "https://docs.google.com/feeds/metadata/default" - "?v=3&alt=json&showroot=true&include-installed-apps=true", - url_generator_.GenerateAccountMetadataUrl(true).spec()); - - // Exclude installed apps. - EXPECT_EQ( - "https://docs.google.com/feeds/metadata/default?v=3&alt=json" - "&showroot=true", - url_generator_.GenerateAccountMetadataUrl(false).spec()); -} - -TEST_F(GDataWapiUrlGeneratorTest, GenerateDownloadFileUrl) { - EXPECT_EQ( - "https://www.googledrive.com/host/resourceId", - url_generator_.GenerateDownloadFileUrl("file:resourceId").spec()); -} - } // namespace google_apis diff --git a/chromium/google_apis/drive/task_util.cc b/chromium/google_apis/drive/task_util.cc index 3f149e434ef..420afacb844 100644 --- a/chromium/google_apis/drive/task_util.cc +++ b/chromium/google_apis/drive/task_util.cc @@ -8,9 +8,9 @@ namespace google_apis { -void RunTaskOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner, +void RunTaskOnThread(scoped_refptr<base::SequencedTaskRunner> task_runner, const base::Closure& task) { - if (task_runner->BelongsToCurrentThread()) { + if (task_runner->RunsTasksOnCurrentThread()) { task.Run(); } else { const bool posted = task_runner->PostTask(FROM_HERE, task); diff --git a/chromium/google_apis/drive/task_util.h b/chromium/google_apis/drive/task_util.h index 443f719694e..3cba9bd2cf4 100644 --- a/chromium/google_apis/drive/task_util.h +++ b/chromium/google_apis/drive/task_util.h @@ -10,8 +10,8 @@ namespace google_apis { -// Runs task on the thread to which |task_runner| belongs. -void RunTaskOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner, +// Runs task on a thread on which |task_runner| may run tasks. +void RunTaskOnThread(scoped_refptr<base::SequencedTaskRunner> task_runner, const base::Closure& task); namespace internal { @@ -95,17 +95,6 @@ struct ComposedCallback<void(T1, T2, T3, T4)> { } }; -// ComposedCallback with four arguments, and the second one is scoped_ptr. -template<typename T1, typename T2, typename D2, typename T3, typename T4> -struct ComposedCallback<void(T1, scoped_ptr<T2, D2>, T3, T4)> { - static void Run( - const base::Callback<void(const base::Closure&)>& runner, - const base::Callback<void(T1, scoped_ptr<T2, D2>, T3, T4)>& callback, - T1 arg1, scoped_ptr<T2, D2> arg2, T3 arg3, T4 arg4) { - runner.Run(base::Bind(callback, arg1, base::Passed(&arg2), arg3, arg4)); - } -}; - } // namespace internal // Returns callback that takes arguments (arg1, arg2, ...), create a closure diff --git a/chromium/google_apis/drive/test_util.cc b/chromium/google_apis/drive/test_util.cc index 20d8ad65a6f..e77d1cf69e8 100644 --- a/chromium/google_apis/drive/test_util.cc +++ b/chromium/google_apis/drive/test_util.cc @@ -57,7 +57,8 @@ void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure) { bool WriteStringToFile(const base::FilePath& file_path, const std::string& content) { - int result = file_util::WriteFile(file_path, content.data(), content.size()); + int result = base::WriteFile( + file_path, content.data(), static_cast<int>(content.size())); return content.size() == static_cast<size_t>(result); } |