Commit d6907a5c authored by kinaba@chromium.org's avatar kinaba@chromium.org

Revert 288017 "Parse Drive API responses all at once in the bloc..."

It broke Drive sync completely.

> Parse Drive API responses all at once in the blocking pool.
> 
> Previous implementation did the parsing of string to base::Value
> on blocking pool, and that of base::Value to specific data types
> either on UI thread or on yet another post to blocking pool.
> 
> The previous implementation is slightly inefficient and moreover
> involves a subtle bug 284244.
> 
> BUG=284244
> 
> Review URL: https://codereview.chromium.org/442193002

TBR=kinaba@chromium.org
BUG=401843

Review URL: https://codereview.chromium.org/449323002

Cr-Commit-Position: refs/heads/master@{#288216}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288216 0039d316-1c4b-4281-b951-d872f2087c98
parent 39cfeda9
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "base/values.h"
#include "chrome/browser/drive/drive_api_util.h" #include "chrome/browser/drive/drive_api_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "google_apis/drive/auth_service.h" #include "google_apis/drive/auth_service.h"
...@@ -146,16 +149,6 @@ void ExtractOpenUrlAndRun(const std::string& app_id, ...@@ -146,16 +149,6 @@ void ExtractOpenUrlAndRun(const std::string& app_id,
callback.Run(GDATA_OTHER_ERROR, GURL()); callback.Run(GDATA_OTHER_ERROR, GURL());
} }
void ExtractShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
google_apis::GDataErrorCode error,
scoped_ptr<google_apis::ResourceEntry> entry) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
const google_apis::Link* share_link =
entry ? entry->GetLinkByType(google_apis::Link::LINK_SHARE) : NULL;
callback.Run(error, share_link ? share_link->href() : GURL());
}
// Ignores the |entry|, and runs the |callback|. // Ignores the |entry|, and runs the |callback|.
void EntryActionCallbackAdapter( void EntryActionCallbackAdapter(
const EntryActionCallback& callback, const EntryActionCallback& callback,
...@@ -383,7 +376,7 @@ CancelCallback DriveAPIService::GetShareUrl( ...@@ -383,7 +376,7 @@ CancelCallback DriveAPIService::GetShareUrl(
wapi_url_generator_, wapi_url_generator_,
resource_id, resource_id,
embed_origin, embed_origin,
base::Bind(&ExtractShareUrlAndRun, base::Bind(&util::ParseShareUrlAndRun,
callback))); callback)));
} }
......
...@@ -136,6 +136,29 @@ std::string CanonicalizeResourceId(const std::string& resource_id) { ...@@ -136,6 +136,29 @@ std::string CanonicalizeResourceId(const std::string& resource_id) {
return resource_id; return resource_id;
} }
void ParseShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
google_apis::GDataErrorCode error,
scoped_ptr<base::Value> value) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!value) {
callback.Run(error, GURL());
return;
}
// Parsing ResourceEntry is cheap enough to do on UI thread.
scoped_ptr<google_apis::ResourceEntry> entry =
google_apis::ResourceEntry::ExtractAndParse(*value);
if (!entry) {
callback.Run(google_apis::GDATA_PARSE_ERROR, GURL());
return;
}
const google_apis::Link* share_link =
entry->GetLinkByType(google_apis::Link::LINK_SHARE);
callback.Run(error, share_link ? share_link->href() : GURL());
}
scoped_ptr<google_apis::ResourceEntry> scoped_ptr<google_apis::ResourceEntry>
ConvertFileResourceToResourceEntry( ConvertFileResourceToResourceEntry(
const google_apis::FileResource& file_resource) { const google_apis::FileResource& file_resource) {
......
...@@ -63,6 +63,12 @@ std::string ExtractResourceIdFromUrl(const GURL& url); ...@@ -63,6 +63,12 @@ std::string ExtractResourceIdFromUrl(const GURL& url);
// into the new format. // into the new format.
std::string CanonicalizeResourceId(const std::string& resource_id); std::string CanonicalizeResourceId(const std::string& resource_id);
// Extracts an url to the sharing dialog and returns it via |callback|. If
// the share url doesn't exist, then an empty url is returned.
void ParseShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
google_apis::GDataErrorCode error,
scoped_ptr<base::Value> value);
// Converts FileResource to ResourceEntry. // Converts FileResource to ResourceEntry.
scoped_ptr<google_apis::ResourceEntry> scoped_ptr<google_apis::ResourceEntry>
ConvertFileResourceToResourceEntry( ConvertFileResourceToResourceEntry(
......
...@@ -43,18 +43,29 @@ const char kUploadResponseLocation[] = "location"; ...@@ -43,18 +43,29 @@ const char kUploadResponseLocation[] = "location";
const char kUploadContentRange[] = "Content-Range: bytes "; const char kUploadContentRange[] = "Content-Range: bytes ";
const char kUploadResponseRange[] = "range"; const char kUploadResponseRange[] = "range";
// Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on // Parse JSON string to base::Value object.
// the calling thread when finished with either success or failure. scoped_ptr<base::Value> ParseJsonInternal(const std::string& json) {
// The callback must not be null. int error_code = -1;
void ParseJsonOnBlockingPool( std::string error_message;
base::TaskRunner* blocking_task_runner, scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
const std::string& json, json, base::JSON_PARSE_RFC, &error_code, &error_message));
const base::Callback<void(scoped_ptr<base::Value> value)>& callback) {
base::PostTaskAndReplyWithResult( if (!value.get()) {
blocking_task_runner, std::string trimmed_json;
FROM_HERE, if (json.size() < 80) {
base::Bind(&google_apis::ParseJson, json), trimmed_json = json;
callback); } else {
// Take the first 50 and the last 10 bytes.
trimmed_json = base::StringPrintf(
"%s [%s bytes] %s",
json.substr(0, 50).c_str(),
base::Uint64ToString(json.size() - 60).c_str(),
json.substr(json.size() - 10).c_str());
}
LOG(WARNING) << "Error while parsing entry response: " << error_message
<< ", code: " << error_code << ", json:\n" << trimmed_json;
}
return value.Pass();
} }
// Returns response headers as a string. Returns a warning message if // Returns response headers as a string. Returns a warning message if
...@@ -84,28 +95,14 @@ bool IsSuccessfulResponseCode(int response_code) { ...@@ -84,28 +95,14 @@ bool IsSuccessfulResponseCode(int response_code) {
namespace google_apis { namespace google_apis {
scoped_ptr<base::Value> ParseJson(const std::string& json) { void ParseJson(base::TaskRunner* blocking_task_runner,
int error_code = -1; const std::string& json,
std::string error_message; const ParseJsonCallback& callback) {
scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( base::PostTaskAndReplyWithResult(
json, base::JSON_PARSE_RFC, &error_code, &error_message)); blocking_task_runner,
FROM_HERE,
if (!value.get()) { base::Bind(&ParseJsonInternal, json),
std::string trimmed_json; callback);
if (json.size() < 80) {
trimmed_json = json;
} else {
// Take the first 50 and the last 10 bytes.
trimmed_json = base::StringPrintf(
"%s [%s bytes] %s",
json.substr(0, 50).c_str(),
base::Uint64ToString(json.size() - 60).c_str(),
json.substr(json.size() - 10).c_str());
}
LOG(WARNING) << "Error while parsing entry response: " << error_message
<< ", code: " << error_code << ", json:\n" << trimmed_json;
}
return value.Pass();
} }
//=========================== ResponseWriter ================================== //=========================== ResponseWriter ==================================
...@@ -362,7 +359,7 @@ void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) { ...@@ -362,7 +359,7 @@ void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded"; const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
const char kErrorReasonQuotaExceeded[] = "quotaExceeded"; const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
scoped_ptr<base::Value> value(ParseJson(response_writer_->data())); scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data()));
base::DictionaryValue* dictionary = NULL; base::DictionaryValue* dictionary = NULL;
base::DictionaryValue* error = NULL; base::DictionaryValue* error = NULL;
if (value && if (value &&
...@@ -437,6 +434,62 @@ void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) { ...@@ -437,6 +434,62 @@ void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
callback_.Run(code); callback_.Run(code);
} }
//============================== GetDataRequest ==============================
GetDataRequest::GetDataRequest(RequestSender* sender,
const GetDataCallback& callback)
: UrlFetchRequestBase(sender),
callback_(callback),
weak_ptr_factory_(this) {
DCHECK(!callback_.is_null());
}
GetDataRequest::~GetDataRequest() {}
void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code,
const std::string& data) {
DCHECK(CalledOnValidThread());
VLOG(1) << "JSON received from " << GetURL().spec() << ": "
<< data.size() << " bytes";
ParseJson(blocking_task_runner(),
data,
base::Bind(&GetDataRequest::OnDataParsed,
weak_ptr_factory_.GetWeakPtr(),
fetch_error_code));
}
void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) {
GDataErrorCode fetch_error_code = GetErrorCode();
switch (fetch_error_code) {
case HTTP_SUCCESS:
case HTTP_CREATED:
ParseResponse(fetch_error_code, response_writer()->data());
break;
default:
RunCallbackOnPrematureFailure(fetch_error_code);
OnProcessURLFetchResultsComplete();
break;
}
}
void GetDataRequest::RunCallbackOnPrematureFailure(
GDataErrorCode fetch_error_code) {
callback_.Run(fetch_error_code, scoped_ptr<base::Value>());
}
void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code,
scoped_ptr<base::Value> value) {
DCHECK(CalledOnValidThread());
if (!value.get())
fetch_error_code = GDATA_PARSE_ERROR;
callback_.Run(fetch_error_code, value.Pass());
OnProcessURLFetchResultsComplete();
}
//========================= InitiateUploadRequestBase ======================== //========================= InitiateUploadRequestBase ========================
InitiateUploadRequestBase::InitiateUploadRequestBase( InitiateUploadRequestBase::InitiateUploadRequestBase(
...@@ -565,7 +618,7 @@ void UploadRangeRequestBase::ProcessURLFetchResults( ...@@ -565,7 +618,7 @@ void UploadRangeRequestBase::ProcessURLFetchResults(
} else if (code == HTTP_CREATED || code == HTTP_SUCCESS) { } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
// The upload is successfully done. Parse the response which should be // The upload is successfully done. Parse the response which should be
// the entry's metadata. // the entry's metadata.
ParseJsonOnBlockingPool(blocking_task_runner(), ParseJson(blocking_task_runner(),
response_writer()->data(), response_writer()->data(),
base::Bind(&UploadRangeRequestBase::OnDataParsed, base::Bind(&UploadRangeRequestBase::OnDataParsed,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
......
...@@ -29,6 +29,10 @@ namespace google_apis { ...@@ -29,6 +29,10 @@ namespace google_apis {
class RequestSender; class RequestSender;
// Callback used to pass parsed JSON from ParseJson(). If parsing error occurs,
// then the passed argument is null.
typedef base::Callback<void(scoped_ptr<base::Value> value)> ParseJsonCallback;
// Callback used for DownloadFileRequest and ResumeUploadRequestBase. // Callback used for DownloadFileRequest and ResumeUploadRequestBase.
typedef base::Callback<void(int64 progress, int64 total)> ProgressCallback; typedef base::Callback<void(int64 progress, int64 total)> ProgressCallback;
...@@ -37,8 +41,12 @@ typedef base::Callback<void( ...@@ -37,8 +41,12 @@ typedef base::Callback<void(
GDataErrorCode error, GDataErrorCode error,
scoped_ptr<std::string> content)> GetContentCallback; scoped_ptr<std::string> content)> GetContentCallback;
// Parses JSON passed in |json|. Returns NULL on failure. // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
scoped_ptr<base::Value> ParseJson(const std::string& json); // the calling thread when finished with either success or failure.
// The callback must not be null.
void ParseJson(base::TaskRunner* blocking_task_runner,
const std::string& json,
const ParseJsonCallback& callback);
//======================= AuthenticatedRequestInterface ====================== //======================= AuthenticatedRequestInterface ======================
...@@ -241,6 +249,45 @@ class EntryActionRequest : public UrlFetchRequestBase { ...@@ -241,6 +249,45 @@ class EntryActionRequest : public UrlFetchRequestBase {
DISALLOW_COPY_AND_ASSIGN(EntryActionRequest); DISALLOW_COPY_AND_ASSIGN(EntryActionRequest);
}; };
//============================== GetDataRequest ==============================
// Callback type for requests that returns JSON data.
typedef base::Callback<void(GDataErrorCode error,
scoped_ptr<base::Value> json_data)> GetDataCallback;
// This class performs the request for fetching and converting the fetched
// content into a base::Value.
class GetDataRequest : public UrlFetchRequestBase {
public:
// |callback| is called when the request finishes either by success or by
// failure. On success, a JSON Value object is passed. It must not be null.
GetDataRequest(RequestSender* sender, const GetDataCallback& callback);
virtual ~GetDataRequest();
protected:
// UrlFetchRequestBase overrides.
virtual void ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE;
virtual void RunCallbackOnPrematureFailure(
GDataErrorCode fetch_error_code) OVERRIDE;
private:
// Parses JSON response.
void ParseResponse(GDataErrorCode fetch_error_code, const std::string& data);
// Called when ParseJsonOnBlockingPool() is completed.
void OnDataParsed(GDataErrorCode fetch_error_code,
scoped_ptr<base::Value> value);
const GetDataCallback callback_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<GetDataRequest> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GetDataRequest);
};
//=========================== InitiateUploadRequestBase======================= //=========================== InitiateUploadRequestBase=======================
// Callback type for DriveServiceInterface::InitiateUpload. // Callback type for DriveServiceInterface::InitiateUpload.
......
...@@ -51,6 +51,24 @@ class FakeUrlFetchRequest : public UrlFetchRequestBase { ...@@ -51,6 +51,24 @@ class FakeUrlFetchRequest : public UrlFetchRequestBase {
GURL url_; GURL url_;
}; };
class FakeGetDataRequest : public GetDataRequest {
public:
explicit FakeGetDataRequest(RequestSender* sender,
const GetDataCallback& callback,
const GURL& url)
: GetDataRequest(sender, callback),
url_(url) {
}
virtual ~FakeGetDataRequest() {
}
protected:
virtual GURL GetURL() const OVERRIDE { return url_; }
GURL url_;
};
} // namespace } // namespace
class BaseRequestsTest : public testing::Test { class BaseRequestsTest : public testing::Test {
...@@ -91,7 +109,11 @@ class BaseRequestsTest : public testing::Test { ...@@ -91,7 +109,11 @@ class BaseRequestsTest : public testing::Test {
}; };
TEST_F(BaseRequestsTest, ParseValidJson) { TEST_F(BaseRequestsTest, ParseValidJson) {
scoped_ptr<base::Value> json(ParseJson(kValidJsonString)); scoped_ptr<base::Value> json;
ParseJson(message_loop_.message_loop_proxy(),
kValidJsonString,
base::Bind(test_util::CreateCopyResultCallback(&json)));
base::RunLoop().RunUntilIdle();
base::DictionaryValue* root_dict = NULL; base::DictionaryValue* root_dict = NULL;
ASSERT_TRUE(json); ASSERT_TRUE(json);
...@@ -103,7 +125,14 @@ TEST_F(BaseRequestsTest, ParseValidJson) { ...@@ -103,7 +125,14 @@ TEST_F(BaseRequestsTest, ParseValidJson) {
} }
TEST_F(BaseRequestsTest, ParseInvalidJson) { TEST_F(BaseRequestsTest, ParseInvalidJson) {
EXPECT_FALSE(ParseJson(kInvalidJsonString)); // Initialize with a valid pointer to verify that null is indeed assigned.
scoped_ptr<base::Value> json(base::Value::CreateNullValue());
ParseJson(message_loop_.message_loop_proxy(),
kInvalidJsonString,
base::Bind(test_util::CreateCopyResultCallback(&json)));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(json);
} }
TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) { TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) {
...@@ -136,4 +165,40 @@ TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) { ...@@ -136,4 +165,40 @@ TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) {
EXPECT_EQ(HTTP_SERVICE_UNAVAILABLE, error); EXPECT_EQ(HTTP_SERVICE_UNAVAILABLE, error);
} }
TEST_F(BaseRequestsTest, GetDataRequestParseValidResponse) {
response_body_ = kValidJsonString;
GDataErrorCode error = GDATA_OTHER_ERROR;
scoped_ptr<base::Value> value;
base::RunLoop run_loop;
sender_->StartRequestWithRetry(
new FakeGetDataRequest(
sender_.get(),
test_util::CreateQuitCallback(
&run_loop, test_util::CreateCopyResultCallback(&error, &value)),
test_server_.base_url()));
run_loop.Run();
EXPECT_EQ(HTTP_SUCCESS, error);
EXPECT_TRUE(value);
}
TEST_F(BaseRequestsTest, GetDataRequestParseInvalidResponse) {
response_body_ = kInvalidJsonString;
GDataErrorCode error = GDATA_OTHER_ERROR;
scoped_ptr<base::Value> value;
base::RunLoop run_loop;
sender_->StartRequestWithRetry(
new FakeGetDataRequest(
sender_.get(),
test_util::CreateQuitCallback(
&run_loop, test_util::CreateCopyResultCallback(&error, &value)),
test_server_.base_url()));
run_loop.Run();
EXPECT_EQ(GDATA_PARSE_ERROR, error);
EXPECT_FALSE(value);
}
} // namespace google_apis } // namespace google_apis
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/task_runner_util.h" #include "base/task_runner_util.h"
#include "base/values.h" #include "base/values.h"
#include "google_apis/drive/drive_api_parser.h"
#include "google_apis/drive/request_sender.h" #include "google_apis/drive/request_sender.h"
#include "google_apis/drive/request_util.h" #include "google_apis/drive/request_util.h"
#include "google_apis/drive/time_util.h" #include "google_apis/drive/time_util.h"
...@@ -22,6 +23,70 @@ namespace { ...@@ -22,6 +23,70 @@ namespace {
const char kContentTypeApplicationJson[] = "application/json"; const char kContentTypeApplicationJson[] = "application/json";
const char kParentLinkKind[] = "drive#fileLink"; const char kParentLinkKind[] = "drive#fileLink";
// Parses the JSON value to a resource typed |T| and runs |callback| on the UI
// thread once parsing is done.
template<typename T>
void ParseJsonAndRun(
const base::Callback<void(GDataErrorCode, scoped_ptr<T>)>& callback,
GDataErrorCode error,
scoped_ptr<base::Value> value) {
DCHECK(!callback.is_null());
scoped_ptr<T> resource;
if (value) {
resource = T::CreateFrom(*value);
if (!resource) {
// Failed to parse the JSON value, although the JSON value is available,
// so let the callback know the parsing error.
error = GDATA_PARSE_ERROR;
}
}
callback.Run(error, resource.Pass());
}
// Thin adapter of T::CreateFrom.
template<typename T>
scoped_ptr<T> ParseJsonOnBlockingPool(scoped_ptr<base::Value> value) {
return T::CreateFrom(*value);
}
// Runs |callback| with given |error| and |value|. If |value| is null,
// overwrites |error| to GDATA_PARSE_ERROR.
template<typename T>
void ParseJsonOnBlockingPoolAndRunAfterBlockingPoolTask(
const base::Callback<void(GDataErrorCode, scoped_ptr<T>)>& callback,
GDataErrorCode error, scoped_ptr<T> value) {
if (!value)
error = GDATA_PARSE_ERROR;
callback.Run(error, value.Pass());
}
// Parses the JSON value to a resource typed |T| and runs |callback| on
// blocking pool, and then run on the current thread.
// TODO(hidehiko): Move this and ParseJsonAndRun defined above into base with
// merging the tasks running on blocking pool into one.
template<typename T>
void ParseJsonOnBlockingPoolAndRun(
scoped_refptr<base::TaskRunner> blocking_task_runner,
const base::Callback<void(GDataErrorCode, scoped_ptr<T>)>& callback,
GDataErrorCode error,
scoped_ptr<base::Value> value) {
DCHECK(!callback.is_null());
if (!value) {
callback.Run(error, scoped_ptr<T>());
return;
}
base::PostTaskAndReplyWithResult(
blocking_task_runner,
FROM_HERE,
base::Bind(&ParseJsonOnBlockingPool<T>, base::Passed(&value)),
base::Bind(&ParseJsonOnBlockingPoolAndRunAfterBlockingPoolTask<T>,
callback, error));
}
// Parses the JSON value to FileResource instance and runs |callback| on the // Parses the JSON value to FileResource instance and runs |callback| on the
// UI thread once parsing is done. // UI thread once parsing is done.
// This is customized version of ParseJsonAndRun defined above to adapt the // This is customized version of ParseJsonAndRun defined above to adapt the
...@@ -61,16 +126,17 @@ scoped_ptr<base::DictionaryValue> CreateParentValue( ...@@ -61,16 +126,17 @@ scoped_ptr<base::DictionaryValue> CreateParentValue(
namespace drive { namespace drive {
//============================ DriveApiPartialFieldRequest ==================== //============================ DriveApiDataRequest ===========================
DriveApiPartialFieldRequest::DriveApiPartialFieldRequest( DriveApiDataRequest::DriveApiDataRequest(RequestSender* sender,
RequestSender* sender) : UrlFetchRequestBase(sender) { const GetDataCallback& callback)
: GetDataRequest(sender, callback) {
} }
DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() { DriveApiDataRequest::~DriveApiDataRequest() {
} }
GURL DriveApiPartialFieldRequest::GetURL() const { GURL DriveApiDataRequest::GetURL() const {
GURL url = GetURLInternal(); GURL url = GetURLInternal();
if (!fields_.empty()) if (!fields_.empty())
url = net::AppendOrReplaceQueryParameter(url, "fields", fields_); url = net::AppendOrReplaceQueryParameter(url, "fields", fields_);
...@@ -83,7 +149,9 @@ FilesGetRequest::FilesGetRequest( ...@@ -83,7 +149,9 @@ FilesGetRequest::FilesGetRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -100,7 +168,9 @@ FilesAuthorizeRequest::FilesAuthorizeRequest( ...@@ -100,7 +168,9 @@ FilesAuthorizeRequest::FilesAuthorizeRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -121,7 +191,9 @@ FilesInsertRequest::FilesInsertRequest( ...@@ -121,7 +191,9 @@ FilesInsertRequest::FilesInsertRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -178,7 +250,9 @@ FilesPatchRequest::FilesPatchRequest( ...@@ -178,7 +250,9 @@ FilesPatchRequest::FilesPatchRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator), url_generator_(url_generator),
set_modified_date_(false), set_modified_date_(false),
update_viewed_date_(true) { update_viewed_date_(true) {
...@@ -246,7 +320,9 @@ FilesCopyRequest::FilesCopyRequest( ...@@ -246,7 +320,9 @@ FilesCopyRequest::FilesCopyRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -299,7 +375,11 @@ FilesListRequest::FilesListRequest( ...@@ -299,7 +375,11 @@ FilesListRequest::FilesListRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileListCallback& callback) const FileListCallback& callback)
: DriveApiDataRequest<FileList>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<FileList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)),
url_generator_(url_generator), url_generator_(url_generator),
max_results_(100) { max_results_(100) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
...@@ -316,7 +396,11 @@ GURL FilesListRequest::GetURLInternal() const { ...@@ -316,7 +396,11 @@ GURL FilesListRequest::GetURLInternal() const {
FilesListNextPageRequest::FilesListNextPageRequest( FilesListNextPageRequest::FilesListNextPageRequest(
RequestSender* sender, RequestSender* sender,
const FileListCallback& callback) const FileListCallback& callback)
: DriveApiDataRequest<FileList>(sender, callback) { : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<FileList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -361,7 +445,9 @@ FilesTrashRequest::FilesTrashRequest( ...@@ -361,7 +445,9 @@ FilesTrashRequest::FilesTrashRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest<FileResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -382,7 +468,9 @@ AboutGetRequest::AboutGetRequest( ...@@ -382,7 +468,9 @@ AboutGetRequest::AboutGetRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const AboutResourceCallback& callback) const AboutResourceCallback& callback)
: DriveApiDataRequest<AboutResource>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<AboutResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -399,7 +487,11 @@ ChangesListRequest::ChangesListRequest( ...@@ -399,7 +487,11 @@ ChangesListRequest::ChangesListRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const ChangeListCallback& callback) const ChangeListCallback& callback)
: DriveApiDataRequest<ChangeList>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<ChangeList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)),
url_generator_(url_generator), url_generator_(url_generator),
include_deleted_(true), include_deleted_(true),
max_results_(100), max_results_(100),
...@@ -419,7 +511,11 @@ GURL ChangesListRequest::GetURLInternal() const { ...@@ -419,7 +511,11 @@ GURL ChangesListRequest::GetURLInternal() const {
ChangesListNextPageRequest::ChangesListNextPageRequest( ChangesListNextPageRequest::ChangesListNextPageRequest(
RequestSender* sender, RequestSender* sender,
const ChangeListCallback& callback) const ChangeListCallback& callback)
: DriveApiDataRequest<ChangeList>(sender, callback) { : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<ChangeList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -437,7 +533,9 @@ AppsListRequest::AppsListRequest( ...@@ -437,7 +533,9 @@ AppsListRequest::AppsListRequest(
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
bool use_internal_endpoint, bool use_internal_endpoint,
const AppListCallback& callback) const AppListCallback& callback)
: DriveApiDataRequest<AppList>(sender, callback), : DriveApiDataRequest(
sender,
base::Bind(&ParseJsonAndRun<AppList>, callback)),
url_generator_(url_generator), url_generator_(url_generator),
use_internal_endpoint_(use_internal_endpoint) { use_internal_endpoint_(use_internal_endpoint) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
......
This diff is collapsed.
...@@ -4,37 +4,22 @@ ...@@ -4,37 +4,22 @@
#include "google_apis/drive/gdata_wapi_requests.h" #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/gdata_wapi_url_generator.h"
namespace google_apis { namespace google_apis {
namespace { //============================ GetResourceEntryRequest =======================
scoped_ptr<ResourceEntry> ParseResourceEntry(const std::string& json) {
scoped_ptr<base::Value> value = ParseJson(json);
return value ? ResourceEntry::ExtractAndParse(*value) :
scoped_ptr<ResourceEntry>();
}
} // namespace
GetResourceEntryRequest::GetResourceEntryRequest( GetResourceEntryRequest::GetResourceEntryRequest(
RequestSender* sender, RequestSender* sender,
const GDataWapiUrlGenerator& url_generator, const GDataWapiUrlGenerator& url_generator,
const std::string& resource_id, const std::string& resource_id,
const GURL& embed_origin, const GURL& embed_origin,
const GetResourceEntryCallback& callback) const GetDataCallback& callback)
: UrlFetchRequestBase(sender), : GetDataRequest(sender, callback),
url_generator_(url_generator), url_generator_(url_generator),
resource_id_(resource_id), resource_id_(resource_id),
embed_origin_(embed_origin), embed_origin_(embed_origin) {
callback_(callback),
weak_ptr_factory_(this) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -45,35 +30,4 @@ GURL GetResourceEntryRequest::GetURL() const { ...@@ -45,35 +30,4 @@ GURL GetResourceEntryRequest::GetURL() const {
resource_id_, embed_origin_); resource_id_, embed_origin_);
} }
void GetResourceEntryRequest::ProcessURLFetchResults(
const net::URLFetcher* source) {
GDataErrorCode error = GetErrorCode();
switch (error) {
case HTTP_SUCCESS:
case HTTP_CREATED:
base::PostTaskAndReplyWithResult(
blocking_task_runner(),
FROM_HERE,
base::Bind(&ParseResourceEntry, response_writer()->data()),
base::Bind(&GetResourceEntryRequest::OnDataParsed,
weak_ptr_factory_.GetWeakPtr(), error));
break;
default:
RunCallbackOnPrematureFailure(error);
OnProcessURLFetchResultsComplete();
break;
}
}
void GetResourceEntryRequest::RunCallbackOnPrematureFailure(
GDataErrorCode error) {
callback_.Run(error, scoped_ptr<ResourceEntry>());
}
void GetResourceEntryRequest::OnDataParsed(GDataErrorCode error,
scoped_ptr<ResourceEntry> entry) {
callback_.Run(entry ? error : GDATA_PARSE_ERROR, entry.Pass());
OnProcessURLFetchResultsComplete();
}
} // namespace google_apis } // namespace google_apis
...@@ -12,44 +12,29 @@ ...@@ -12,44 +12,29 @@
namespace google_apis { namespace google_apis {
class ResourceEntry; //========================= GetResourceEntryRequest ==========================
// Callback type for GetResourceEntryRequest.
typedef base::Callback<void(GDataErrorCode error,
scoped_ptr<ResourceEntry> entry)>
GetResourceEntryCallback;
// This class performs the request for fetching a single resource entry. // This class performs the request for fetching a single resource entry.
class GetResourceEntryRequest : public UrlFetchRequestBase { class GetResourceEntryRequest : public GetDataRequest {
public: public:
// |callback| must not be null. // |callback| must not be null.
GetResourceEntryRequest(RequestSender* sender, GetResourceEntryRequest(RequestSender* sender,
const GDataWapiUrlGenerator& url_generator, const GDataWapiUrlGenerator& url_generator,
const std::string& resource_id, const std::string& resource_id,
const GURL& embed_origin, const GURL& embed_origin,
const GetResourceEntryCallback& callback); const GetDataCallback& callback);
virtual ~GetResourceEntryRequest(); virtual ~GetResourceEntryRequest();
protected: protected:
// UrlFetchRequestBase overrides. // UrlFetchRequestBase overrides.
virtual void ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE;
virtual void RunCallbackOnPrematureFailure(GDataErrorCode error) OVERRIDE;
virtual GURL GetURL() const OVERRIDE; virtual GURL GetURL() const OVERRIDE;
private: private:
void OnDataParsed(GDataErrorCode error, scoped_ptr<ResourceEntry> entry);
const GDataWapiUrlGenerator url_generator_; const GDataWapiUrlGenerator url_generator_;
// Resource id of the requested entry. // Resource id of the requested entry.
const std::string resource_id_; const std::string resource_id_;
// Embed origin for an url to the sharing dialog. Can be empty. // Embed origin for an url to the sharing dialog. Can be empty.
GURL embed_origin_; const GURL& embed_origin_;
const GetResourceEntryCallback callback_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<GetResourceEntryRequest> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GetResourceEntryRequest); DISALLOW_COPY_AND_ASSIGN(GetResourceEntryRequest);
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/values.h"
#include "google_apis/drive/dummy_auth_service.h" #include "google_apis/drive/dummy_auth_service.h"
#include "google_apis/drive/gdata_wapi_parser.h" #include "google_apis/drive/gdata_wapi_parser.h"
#include "google_apis/drive/gdata_wapi_requests.h" #include "google_apis/drive/gdata_wapi_requests.h"
...@@ -98,7 +99,7 @@ class GDataWapiRequestsTest : public testing::Test { ...@@ -98,7 +99,7 @@ class GDataWapiRequestsTest : public testing::Test {
TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) { TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) {
GDataErrorCode result_code = GDATA_OTHER_ERROR; GDataErrorCode result_code = GDATA_OTHER_ERROR;
scoped_ptr<ResourceEntry> result_data; scoped_ptr<base::Value> result_data;
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -119,14 +120,16 @@ TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) { ...@@ -119,14 +120,16 @@ TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) {
EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id" EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
"?v=3&alt=json&showroot=true", "?v=3&alt=json&showroot=true",
http_request_.relative_url); http_request_.relative_url);
scoped_ptr<base::Value> expected_json =
test_util::LoadJSONFile("gdata/file_entry.json");
ASSERT_TRUE(expected_json);
EXPECT_TRUE(result_data); EXPECT_TRUE(result_data);
EXPECT_EQ("File 1.mp3", result_data->filename()); EXPECT_TRUE(base::Value::Equals(expected_json.get(), result_data.get()));
EXPECT_EQ("3b4382ebefec6e743578c76bbd0575ce", result_data->file_md5());
} }
TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_InvalidResourceId) { TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_InvalidResourceId) {
GDataErrorCode result_code = GDATA_OTHER_ERROR; GDataErrorCode result_code = GDATA_OTHER_ERROR;
scoped_ptr<ResourceEntry> result_data; scoped_ptr<base::Value> result_data;
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment