Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(880)

Unified Diff: chrome/browser/drive/fake_drive_service.cc

Issue 17140009: Support contents upload on FakeDriveService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: drop unused line Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | chrome/browser/drive/fake_drive_service_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/drive/fake_drive_service.cc
diff --git a/chrome/browser/drive/fake_drive_service.cc b/chrome/browser/drive/fake_drive_service.cc
index 90fd132a9497b852e872eedd12ae2ec8e8976e9b..3df7ba8abe4bd364a99d1af92c56a3079a7f0d2f 100644
--- a/chrome/browser/drive/fake_drive_service.cc
+++ b/chrome/browser/drive/fake_drive_service.cc
@@ -6,7 +6,9 @@
#include <string>
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/md5.h"
#include "base/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -96,28 +98,6 @@ bool EntryMatchWithQuery(const ResourceEntry& entry,
return true;
}
-// Gets the upload URL from the given entry. Returns an empty URL if not
-// found.
-GURL GetUploadUrl(const base::DictionaryValue& entry) {
- std::string upload_url;
- const base::ListValue* links = NULL;
- if (entry.GetList("link", &links) && links) {
- for (size_t link_index = 0;
- link_index < links->GetSize();
- ++link_index) {
- const base::DictionaryValue* link = NULL;
- std::string rel;
- if (links->GetDictionary(link_index, &link) &&
- link && link->GetString("rel", &rel) &&
- rel == kUploadUrlRel &&
- link->GetString("href", &upload_url)) {
- break;
- }
- }
- }
- return GURL(upload_url);
-}
-
// Returns |url| without query parameter.
GURL RemoveQueryParameter(const GURL& url) {
GURL::Replacements replacements;
@@ -125,11 +105,57 @@ GURL RemoveQueryParameter(const GURL& url) {
return url.ReplaceComponents(replacements);
}
+void ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
+ int64 start_position,
+ int64 end_position,
+ GDataErrorCode error,
+ scoped_ptr<ResourceEntry> entry) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ UploadRangeResponse(error,
+ start_position,
+ end_position),
+ base::Passed(&entry)));
+}
+
} // namespace
+struct FakeDriveService::UploadSession {
+ std::string content_type;
+ int64 content_length;
+ std::string parent_resource_id;
+ std::string resource_id;
+ std::string etag;
+ std::string title;
+
+ int64 uploaded_size;
+
+ UploadSession()
+ : content_length(0),
+ uploaded_size(0) {}
+
+ UploadSession(
+ std::string content_type,
+ int64 content_length,
+ std::string parent_resource_id,
+ std::string resource_id,
+ std::string etag,
+ std::string title)
+ : content_type(content_type),
+ content_length(content_length),
+ parent_resource_id(parent_resource_id),
+ resource_id(resource_id),
+ etag(etag),
+ title(title),
+ uploaded_size(0) {
+ }
+};
+
FakeDriveService::FakeDriveService()
: largest_changestamp_(0),
published_date_seq_(0),
+ next_upload_sequence_number_(0),
default_max_results_(0),
resource_id_count_(0),
resource_list_load_count_(0),
@@ -547,7 +573,6 @@ CancelCallback FakeDriveService::DownloadFile(
// Write "x"s of the file size specified in the entry.
std::string file_size_string;
entry->GetString("docs$size.$t", &file_size_string);
- // TODO(satorux): To be correct, we should update docs$md5Checksum.$t here.
int64 file_size = 0;
if (base::StringToInt64(file_size_string, &file_size)) {
base::BinaryValue* content_binary_data;
@@ -649,7 +674,7 @@ CancelCallback FakeDriveService::CopyResource(
link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
links->Append(link);
- AddNewChangestamp(copied_entry.get());
+ AddNewChangestampAndETag(copied_entry.get());
// Parse the new entry.
scoped_ptr<ResourceEntry> resource_entry =
@@ -700,7 +725,7 @@ CancelCallback FakeDriveService::RenameResource(
base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
if (entry) {
entry->SetString("title.$t", new_name);
- AddNewChangestamp(entry);
+ AddNewChangestampAndETag(entry);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
return CancelCallback();
@@ -742,7 +767,7 @@ CancelCallback FakeDriveService::TouchResource(
util::FormatTimeAsString(modified_date));
entry->SetString("gd$lastViewed.$t",
util::FormatTimeAsString(last_viewed_by_me_date));
- AddNewChangestamp(entry);
+ AddNewChangestampAndETag(entry);
scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
base::MessageLoop::current()->PostTask(
@@ -782,7 +807,7 @@ CancelCallback FakeDriveService::AddResourceToDirectory(
"href", GetFakeLinkUrl(parent_resource_id).spec());
links->Append(link);
- AddNewChangestamp(entry);
+ AddNewChangestampAndETag(entry);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
return CancelCallback();
@@ -821,7 +846,7 @@ CancelCallback FakeDriveService::RemoveResourceFromDirectory(
rel == "http://schemas.google.com/docs/2007#parent" &&
GURL(href) == parent_content_url) {
links->Remove(i, NULL);
- AddNewChangestamp(entry);
+ AddNewChangestampAndETag(entry);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
return CancelCallback();
@@ -890,27 +915,25 @@ CancelCallback FakeDriveService::InitiateUploadNewFile(
return CancelCallback();
}
- // Content length should be zero, as we'll create an empty file first. The
- // content will be added in ResumeUpload().
- const base::DictionaryValue* new_entry = AddNewEntry(content_type,
- "", // content_data
- parent_resource_id,
- title,
- false, // shared_with_me
- "file");
- if (!new_entry) {
+ if (parent_resource_id != GetRootResourceId() &&
+ !FindEntryByResourceId(parent_resource_id)) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(callback, HTTP_NOT_FOUND, GURL()));
return CancelCallback();
}
- const GURL upload_url = GetUploadUrl(*new_entry);
- DCHECK(upload_url.is_valid());
+
+ GURL session_url = GetNewUploadSessionUrl();
+ upload_sessions_[session_url] =
+ UploadSession(content_type, content_length,
+ parent_resource_id,
+ "", // resource_id
+ "", // etag
+ title);
base::MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(callback, HTTP_SUCCESS,
- net::AppendQueryParameter(upload_url, "mode", "newfile")));
+ base::Bind(callback, HTTP_SUCCESS, session_url));
return CancelCallback();
}
@@ -946,15 +969,18 @@ CancelCallback FakeDriveService::InitiateUploadExistingFile(
base::Bind(callback, HTTP_PRECONDITION, GURL()));
return CancelCallback();
}
- entry->SetString("docs$size.$t", "0");
- const GURL upload_url = GetUploadUrl(*entry);
- DCHECK(upload_url.is_valid());
+ GURL session_url = GetNewUploadSessionUrl();
+ upload_sessions_[session_url] =
+ UploadSession(content_type, content_length,
+ "", // parent_resource_id
+ resource_id,
+ entry_etag,
+ "" /* title */);
base::MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(callback, HTTP_SUCCESS,
- net::AppendQueryParameter(upload_url, "mode", "existing")));
+ base::Bind(callback, HTTP_SUCCESS, session_url));
return CancelCallback();
}
@@ -979,51 +1005,29 @@ CancelCallback FakeDriveService::ResumeUpload(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- scoped_ptr<ResourceEntry> result_entry;
+ GetResourceEntryCallback completion_callback
+ = base::Bind(&ScheduleUploadRangeCallback,
+ callback, start_position, end_position);
if (offline_) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback,
- UploadRangeResponse(GDATA_NO_CONNECTION,
- start_position,
- end_position),
- base::Passed(&result_entry)));
+ completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
return CancelCallback();
}
- DictionaryValue* entry = NULL;
- entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url));
- if (!entry) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback,
- UploadRangeResponse(HTTP_NOT_FOUND,
- start_position,
- end_position),
- base::Passed(&result_entry)));
+ if (!upload_sessions_.count(upload_url)) {
+ completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
return CancelCallback();
}
+ UploadSession* session = &upload_sessions_[upload_url];
+
// Chunks are required to be sent in such a ways that they fill from the start
// of the not-yet-uploaded part with no gaps nor overlaps.
- std::string current_size_string;
- int64 current_size;
- if (!entry->GetString("docs$size.$t", &current_size_string) ||
- !base::StringToInt64(current_size_string, &current_size) ||
- current_size != start_position) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback,
- UploadRangeResponse(HTTP_BAD_REQUEST,
- start_position,
- end_position),
- base::Passed(&result_entry)));
+ if (session->uploaded_size != start_position) {
+ completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
return CancelCallback();
}
- entry->SetString("docs$size.$t", base::Int64ToString(end_position));
-
if (!progress_callback.is_null()) {
// In the real GDataWapi/Drive DriveService, progress is reported in
// nondeterministic timing. In this fake implementation, we choose to call
@@ -1039,35 +1043,62 @@ CancelCallback FakeDriveService::ResumeUpload(
}
if (content_length != end_position) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback,
- UploadRangeResponse(HTTP_RESUME_INCOMPLETE,
- start_position,
- end_position),
- base::Passed(&result_entry)));
+ session->uploaded_size = end_position;
+ completion_callback.Run(HTTP_RESUME_INCOMPLETE,
+ scoped_ptr<ResourceEntry>());
return CancelCallback();
}
- AddNewChangestamp(entry);
- result_entry = ResourceEntry::CreateFrom(*entry).Pass();
+ std::string content_data;
+ if (!file_util::ReadFileToString(local_file_path, &content_data)) {
+ session->uploaded_size = end_position;
+ completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
+ return CancelCallback();
+ }
+ session->uploaded_size = end_position;
+
+ // |resource_id| is empty if the upload is for new file.
+ if (session->resource_id.empty()) {
+ DCHECK(!session->parent_resource_id.empty());
+ DCHECK(!session->title.empty());
+ const DictionaryValue* new_entry = AddNewEntry(
+ session->content_type,
+ content_data,
+ session->parent_resource_id,
+ session->title,
+ false, // shared_with_me
+ "file");
+ if (!new_entry) {
+ completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
+ return CancelCallback();
+ }
- std::string upload_mode;
- bool upload_mode_found =
- net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode);
- DCHECK(upload_mode_found &&
- (upload_mode == "newfile" || upload_mode == "existing"));
+ completion_callback.Run(HTTP_CREATED,
+ ResourceEntry::CreateFrom(*new_entry));
+ return CancelCallback();
+ }
- GDataErrorCode return_code =
- upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS;
+ DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
+ if (!entry) {
+ completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
+ return CancelCallback();
+ }
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback,
- UploadRangeResponse(return_code,
- start_position,
- end_position),
- base::Passed(&result_entry)));
+ std::string entry_etag;
+ entry->GetString("gd$etag", &entry_etag);
+ if (entry_etag.empty() || session->etag != entry_etag) {
+ completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
+ return CancelCallback();
+ }
+
+ entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
+ entry->Set("test$data",
+ base::BinaryValue::CreateWithCopiedBuffer(
+ content_data.data(), content_data.size()));
+ entry->SetString("docs$size.$t", base::Int64ToString(end_position));
+ AddNewChangestampAndETag(entry);
+
+ completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
return CancelCallback();
}
@@ -1209,40 +1240,6 @@ base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
return NULL;
}
-base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl(
- const GURL& upload_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- base::ListValue* entries = NULL;
- // Go through entries and return the one that matches |upload_url|.
- if (resource_list_value_->GetList("entry", &entries)) {
- for (size_t i = 0; i < entries->GetSize(); ++i) {
- base::DictionaryValue* entry = NULL;
- base::ListValue* links = NULL;
- if (entries->GetDictionary(i, &entry) &&
- entry->GetList("link", &links) &&
- links) {
- for (size_t link_index = 0;
- link_index < links->GetSize();
- ++link_index) {
- base::DictionaryValue* link = NULL;
- std::string rel;
- std::string found_upload_url;
- if (links->GetDictionary(link_index, &link) &&
- link && link->GetString("rel", &rel) &&
- rel == kUploadUrlRel &&
- link->GetString("href", &found_upload_url) &&
- GURL(found_upload_url) == upload_url) {
- return entry;
- }
- }
- }
- }
- }
-
- return NULL;
-}
-
std::string FakeDriveService::GetNewResourceId() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -1250,10 +1247,12 @@ std::string FakeDriveService::GetNewResourceId() {
return base::StringPrintf("resource_id_%d", resource_id_count_);
}
-void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) {
+void FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
++largest_changestamp_;
entry->SetString("docs$changestamp.value",
base::Int64ToString(largest_changestamp_));
+ entry->SetString("gd$etag",
+ "etag_" + base::Int64ToString(largest_changestamp_));
}
const base::DictionaryValue* FakeDriveService::AddNewEntry(
@@ -1285,9 +1284,8 @@ const base::DictionaryValue* FakeDriveService::AddNewEntry(
content_data.c_str(), content_data.size()));
new_entry->SetString("docs$size.$t",
base::Int64ToString(content_data.size()));
- // TODO(satorux): Set the correct MD5 here.
new_entry->SetString("docs$md5Checksum.$t",
- "3b4385ebefec6e743574c76bbd0575de");
+ base::MD5String(content_data));
}
// Add "category" which sets the resource type to |entry_kind|.
@@ -1336,7 +1334,7 @@ const base::DictionaryValue* FakeDriveService::AddNewEntry(
links->Append(upload_link);
new_entry->Set("link", links);
- AddNewChangestamp(new_entry.get());
+ AddNewChangestampAndETag(new_entry.get());
base::Time published_date =
base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
@@ -1472,4 +1470,9 @@ void FakeDriveService::GetResourceListInternal(
base::Passed(&resource_list)));
}
+GURL FakeDriveService::GetNewUploadSessionUrl() {
+ return GURL("https://upload_session_url/" +
+ base::Int64ToString(next_upload_sequence_number_++));
+}
+
} // namespace drive
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | chrome/browser/drive/fake_drive_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698