diff options
author | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-27 21:07:24 +0000 |
---|---|---|
committer | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-27 21:07:24 +0000 |
commit | eaab7a3cc36ce7b3def0244a24d2823ec8baff91 (patch) | |
tree | ad7bda7001c65de74e0b7d72b05483fa4305f391 /chrome/browser/chromeos | |
parent | 3e4d15aad961909fd541ea553bf9382dcfd016ea (diff) | |
download | chromium_src-eaab7a3cc36ce7b3def0244a24d2823ec8baff91.zip chromium_src-eaab7a3cc36ce7b3def0244a24d2823ec8baff91.tar.gz chromium_src-eaab7a3cc36ce7b3def0244a24d2823ec8baff91.tar.bz2 |
Merge 142912 - gdata: Add upload_url() to GDataFile.
Per "Updating document or file content with the resumable protocol"
section in the Google Documents List API version 3.0 [1], we should
use "resumable-edit-media" URLs for updating existing files.
Since we did not store the resumable-edit-media URLs in the existing
protobuf files, we need to reject these files at the loading time.
[1] https://developers.google.com/google-apps/documents-list/
BUG=127080
TEST=added some unit tests; open google drive with older protobuf. confirm that loading of the protobuf failed (error from gdata_files.cc is emitted) but everything works just fine as we fetch the feeds from the server
Review URL: https://chromiumcodereview.appspot.com/10583006
TBR=satorux@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10696017
git-svn-id: svn://svn.chromium.org/chrome/branches/1180/src@144553 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata.proto | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc | 3 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_files.cc | 34 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_files.h | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_files_unittest.cc | 85 |
5 files changed, 123 insertions, 7 deletions
diff --git a/chrome/browser/chromeos/gdata/gdata.proto b/chrome/browser/chromeos/gdata/gdata.proto index 68e20fb..a0ac9a3 100644 --- a/chrome/browser/chromeos/gdata/gdata.proto +++ b/chrome/browser/chromeos/gdata/gdata.proto @@ -42,6 +42,9 @@ message GDataFileProto { optional string id = 7; optional string file_md5 = 8; optional string document_extension = 9; + // This is "resumable-edit-media" URL, used to update an existing file. + // See https://developers.google.com/google-apps/documents-list/ + optional string upload_url = 11; optional bool is_hosted_document = 10; } @@ -50,6 +53,7 @@ message GDataDirectoryProto { optional GDataEntryProto gdata_entry = 1; optional string start_feed_url = 3; optional string next_feed_url = 4; + // This is "resumable-create-media" URL, used to upload a new file. optional string upload_url = 5; optional uint32 origin = 6; repeated GDataDirectoryProto child_directories = 7; diff --git a/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc b/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc index 195249f..2795e68 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc +++ b/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc @@ -1102,6 +1102,7 @@ class GDataFileSystemTest : public testing::Test { // drive/File1 GDataFileProto* file = root_dir->add_child_files(); + file->set_upload_url("http://resumable-edit-media/1"); file_base = file->mutable_gdata_entry(); platform_info = file_base->mutable_file_info(); file_base->set_title("File1"); @@ -1117,6 +1118,7 @@ class GDataFileSystemTest : public testing::Test { // drive/Dir1/File2 file = dir1->add_child_files(); + file->set_upload_url("http://resumable-edit-media/2"); file_base = file->mutable_gdata_entry(); platform_info = file_base->mutable_file_info(); file_base->set_title("File2"); @@ -1132,6 +1134,7 @@ class GDataFileSystemTest : public testing::Test { // drive/Dir1/SubDir2/File3 file = dir2->add_child_files(); + file->set_upload_url("http://resumable-edit-media/3"); file_base = file->mutable_gdata_entry(); platform_info = file_base->mutable_file_info(); file_base->set_title("File3"); diff --git a/chrome/browser/chromeos/gdata/gdata_files.cc b/chrome/browser/chromeos/gdata/gdata_files.cc index 67e65dc..b8759d2 100644 --- a/chrome/browser/chromeos/gdata/gdata_files.cc +++ b/chrome/browser/chromeos/gdata/gdata_files.cc @@ -147,6 +147,12 @@ GDataEntry* GDataFile::FromDocumentEntry(GDataDirectory* parent, if (doc->is_file()) { file->file_info_.size = doc->file_size(); file->file_md5_ = doc->file_md5(); + + // The resumable-edit-media link should only be present for regualar + // files as hosted documents are not uploadable. + const Link* upload_link = doc->GetLinkByType(Link::RESUMABLE_EDIT_MEDIA); + if (upload_link) + file->upload_url_ = upload_link->href(); } else { // ... a hosted document. // Attach .g<something> extension to hosted documents so we can special @@ -570,6 +576,14 @@ bool GDataFile::FromProto(const GDataFileProto& proto) { id_ = proto.id(); file_md5_ = proto.file_md5(); document_extension_ = proto.document_extension(); + // Reject older protobuf that does not contain the upload URL. This URL is + // necessary for uploading dirty files (ex. updating existing files). + if (!proto.has_upload_url()) { + LOG(ERROR) << "Incompatible proto detected (no upload URL): " + << proto.gdata_entry().title(); + return false; + } + upload_url_ = GURL(proto.upload_url()); is_hosted_document_ = proto.is_hosted_document(); return true; @@ -586,19 +600,15 @@ void GDataFile::ToProto(GDataFileProto* proto) const { proto->set_id(id_); proto->set_file_md5(file_md5_); proto->set_document_extension(document_extension_); + // The upload URL must be stored even if it's empty, as this is used to + // detect older protobuf. See FromProto() above. + proto->set_upload_url(upload_url_.spec()); proto->set_is_hosted_document(is_hosted_document_); } bool GDataDirectory::FromProto(const GDataDirectoryProto& proto) { DCHECK(proto.gdata_entry().file_info().is_directory()); - if (!GDataEntry::FromProto(proto.gdata_entry())) - return false; - - start_feed_url_ = GURL(proto.start_feed_url()); - next_feed_url_ = GURL(proto.next_feed_url()); - upload_url_ = GURL(proto.upload_url()); - origin_ = ContentOrigin(proto.origin()); for (int i = 0; i < proto.child_files_size(); ++i) { scoped_ptr<GDataFile> file(new GDataFile(this, root_)); if (!file->FromProto(proto.child_files(i))) { @@ -616,6 +626,16 @@ bool GDataDirectory::FromProto(const GDataDirectoryProto& proto) { AddEntry(dir.release()); } + // The states of the directory should be updated after children are + // handled successfully, so that incomplete states are not left. + if (!GDataEntry::FromProto(proto.gdata_entry())) + return false; + + start_feed_url_ = GURL(proto.start_feed_url()); + next_feed_url_ = GURL(proto.next_feed_url()); + upload_url_ = GURL(proto.upload_url()); + origin_ = ContentOrigin(proto.origin()); + return true; } diff --git a/chrome/browser/chromeos/gdata/gdata_files.h b/chrome/browser/chromeos/gdata/gdata_files.h index ce73e27..deed878 100644 --- a/chrome/browser/chromeos/gdata/gdata_files.h +++ b/chrome/browser/chromeos/gdata/gdata_files.h @@ -216,6 +216,7 @@ class GDataFile : public GDataEntry { DocumentEntry::EntryKind kind() const { return kind_; } const GURL& thumbnail_url() const { return thumbnail_url_; } const GURL& alternate_url() const { return alternate_url_; } + const GURL& upload_url() const { return upload_url_; } const std::string& content_mime_type() const { return content_mime_type_; } const std::string& etag() const { return etag_; } const std::string& id() const { return id_; } @@ -235,6 +236,9 @@ class GDataFile : public GDataEntry { DocumentEntry::EntryKind kind_; GURL thumbnail_url_; GURL alternate_url_; + // Upload url, corresponds to resumable-edit-media link, used for updating + // the content of the file. + GURL upload_url_; std::string content_mime_type_; std::string etag_; std::string id_; diff --git a/chrome/browser/chromeos/gdata/gdata_files_unittest.cc b/chrome/browser/chromeos/gdata/gdata_files_unittest.cc index d7c6fdf..bbfb1c9 100644 --- a/chrome/browser/chromeos/gdata/gdata_files_unittest.cc +++ b/chrome/browser/chromeos/gdata/gdata_files_unittest.cc @@ -12,6 +12,28 @@ namespace gdata { +namespace { + +const char kResumableEditMediaUrl[] = "http://resumable-edit-media/"; + +} // namespace + +TEST(GDataFileTest, FromProto_DetectBadUploadUrl) { + GDataFileProto proto; + proto.mutable_gdata_entry()->set_title("test.txt"); + + GDataFile file(NULL, NULL); + // This should fail as the upload URL is empty. + ASSERT_FALSE(file.FromProto(proto)); + + // Set a upload URL. + proto.set_upload_url(kResumableEditMediaUrl); + + // This should succeed as the resource ID is correct. + ASSERT_TRUE(file.FromProto(proto)); + EXPECT_EQ(kResumableEditMediaUrl, file.upload_url().spec()); +} + TEST(GDataRootDirectoryTest, ParseFromString_DetectBadTitle) { GDataRootDirectoryProto proto; GDataEntryProto* mutable_entry = @@ -71,6 +93,69 @@ TEST(GDataRootDirectoryTest, ParseFromString_DetectBadResourceID) { EXPECT_EQ(kGDataRootDirectoryResourceId, root.resource_id()); } +// We have a similar test in FromProto_DetectBadUploadUrl, but the test here +// is to ensure that an error in GDataFile::FromProto() is properly +// propagated to GDataRootDirectory::ParseFromString(). +TEST(GDataRootDirectoryTest, ParseFromString_DetectNoUploadUrl) { + // Set up the root directory properly. + GDataRootDirectoryProto root_directory_proto; + GDataEntryProto* mutable_entry = + root_directory_proto.mutable_gdata_directory()->mutable_gdata_entry(); + mutable_entry->mutable_file_info()->set_is_directory(true); + mutable_entry->set_title(kGDataRootDirectory); + mutable_entry->set_resource_id(kGDataRootDirectoryResourceId); + // Set the origin to the server. + root_directory_proto.mutable_gdata_directory()->set_origin(FROM_SERVER); + + // Add an empty sub directory under the root directory. This directory is + // added to ensure that nothing is left when the parsing failed. + GDataDirectoryProto* sub_directory_proto = + root_directory_proto.mutable_gdata_directory()->add_child_directories(); + sub_directory_proto->mutable_gdata_entry()->mutable_file_info()-> + set_is_directory(true); + sub_directory_proto->mutable_gdata_entry()->set_title("empty"); + + // Add a sub directory under the root directory. + sub_directory_proto = + root_directory_proto.mutable_gdata_directory()->add_child_directories(); + sub_directory_proto->mutable_gdata_entry()->mutable_file_info()-> + set_is_directory(true); + sub_directory_proto->mutable_gdata_entry()->set_title("dir"); + + // Add a new file under the sub directory "dir". + GDataFileProto* file_proto = + sub_directory_proto->add_child_files(); + file_proto->mutable_gdata_entry()->set_title("test.txt"); + + GDataRootDirectory root; + // The origin is set to UNINITIALIZED by default. + ASSERT_EQ(UNINITIALIZED, root.origin()); + std::string serialized_proto; + // Serialize the proto and check if it's loaded. + // This should fail as the upload URL is not set for |file_proto|. + ASSERT_TRUE(root_directory_proto.SerializeToString(&serialized_proto)); + ASSERT_FALSE(root.ParseFromString(serialized_proto)); + // Nothing should be added to the root directory if the parse failed. + ASSERT_TRUE(root.child_files().empty()); + ASSERT_TRUE(root.child_directories().empty()); + // The origin should remain UNINITIALIZED because the loading failed. + ASSERT_EQ(UNINITIALIZED, root.origin()); + + // Set an upload URL. + file_proto->set_upload_url(kResumableEditMediaUrl); + + // Serialize the proto and check if it's loaded. + // This should succeed as the upload URL is set for |file_proto|. + ASSERT_TRUE(root_directory_proto.SerializeToString(&serialized_proto)); + ASSERT_TRUE(root.ParseFromString(serialized_proto)); + // No file should be added to the root directory. + ASSERT_TRUE(root.child_files().empty()); + // Two directories ("empty", "dir") should be added to the root directory. + ASSERT_EQ(2U, root.child_directories().size()); + // The origin should change to FROM_CACHE because we loaded from the cache. + ASSERT_EQ(FROM_CACHE, root.origin()); +} + TEST(GDataRootDirectoryTest, RefreshFile) { GDataRootDirectory root; // Add a directory to the file system. |