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

Reland: 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, 401843

This CL once landed as r288017 (Patch Set 4) and reverted.
This is the second try.

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

Cr-Commit-Position: refs/heads/master@{#288275}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288275 0039d316-1c4b-4281-b951-d872f2087c98
parent fe928be9
...@@ -8,10 +8,7 @@ ...@@ -8,10 +8,7 @@
#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"
...@@ -149,6 +146,16 @@ void ExtractOpenUrlAndRun(const std::string& app_id, ...@@ -149,6 +146,16 @@ 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,
...@@ -376,7 +383,7 @@ CancelCallback DriveAPIService::GetShareUrl( ...@@ -376,7 +383,7 @@ CancelCallback DriveAPIService::GetShareUrl(
wapi_url_generator_, wapi_url_generator_,
resource_id, resource_id,
embed_origin, embed_origin,
base::Bind(&util::ParseShareUrlAndRun, base::Bind(&ExtractShareUrlAndRun,
callback))); callback)));
} }
......
...@@ -136,29 +136,6 @@ std::string CanonicalizeResourceId(const std::string& resource_id) { ...@@ -136,29 +136,6 @@ 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,12 +63,6 @@ std::string ExtractResourceIdFromUrl(const GURL& url); ...@@ -63,12 +63,6 @@ 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,29 +43,18 @@ const char kUploadResponseLocation[] = "location"; ...@@ -43,29 +43,18 @@ const char kUploadResponseLocation[] = "location";
const char kUploadContentRange[] = "Content-Range: bytes "; const char kUploadContentRange[] = "Content-Range: bytes ";
const char kUploadResponseRange[] = "range"; const char kUploadResponseRange[] = "range";
// Parse JSON string to base::Value object. // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
scoped_ptr<base::Value> ParseJsonInternal(const std::string& json) { // the calling thread when finished with either success or failure.
int error_code = -1; // The callback must not be null.
std::string error_message; void ParseJsonOnBlockingPool(
scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( base::TaskRunner* blocking_task_runner,
json, base::JSON_PARSE_RFC, &error_code, &error_message)); const std::string& json,
const base::Callback<void(scoped_ptr<base::Value> value)>& callback) {
if (!value.get()) { base::PostTaskAndReplyWithResult(
std::string trimmed_json; blocking_task_runner,
if (json.size() < 80) { FROM_HERE,
trimmed_json = json; base::Bind(&google_apis::ParseJson, json),
} else { callback);
// 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
...@@ -95,14 +84,28 @@ bool IsSuccessfulResponseCode(int response_code) { ...@@ -95,14 +84,28 @@ bool IsSuccessfulResponseCode(int response_code) {
namespace google_apis { namespace google_apis {
void ParseJson(base::TaskRunner* blocking_task_runner, scoped_ptr<base::Value> ParseJson(const std::string& json) {
const std::string& json, int error_code = -1;
const ParseJsonCallback& callback) { std::string error_message;
base::PostTaskAndReplyWithResult( scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
blocking_task_runner, json, base::JSON_PARSE_RFC, &error_code, &error_message));
FROM_HERE,
base::Bind(&ParseJsonInternal, json), if (!value.get()) {
callback); std::string trimmed_json;
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 ==================================
...@@ -359,7 +362,7 @@ void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) { ...@@ -359,7 +362,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(ParseJsonInternal(response_writer_->data())); scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
base::DictionaryValue* dictionary = NULL; base::DictionaryValue* dictionary = NULL;
base::DictionaryValue* error = NULL; base::DictionaryValue* error = NULL;
if (value && if (value &&
...@@ -434,62 +437,6 @@ void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) { ...@@ -434,62 +437,6 @@ 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(
...@@ -618,11 +565,11 @@ void UploadRangeRequestBase::ProcessURLFetchResults( ...@@ -618,11 +565,11 @@ 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.
ParseJson(blocking_task_runner(), ParseJsonOnBlockingPool(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(),
code)); code));
} else { } else {
// Failed to upload. Run callbacks to notify the error. // Failed to upload. Run callbacks to notify the error.
OnRangeRequestComplete( OnRangeRequestComplete(
......
...@@ -29,10 +29,6 @@ namespace google_apis { ...@@ -29,10 +29,6 @@ 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;
...@@ -41,12 +37,8 @@ typedef base::Callback<void( ...@@ -41,12 +37,8 @@ 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| on |blocking_task_runner|. Runs |callback| on // Parses JSON passed in |json|. Returns NULL on failure.
// the calling thread when finished with either success or failure. scoped_ptr<base::Value> ParseJson(const std::string& json);
// The callback must not be null.
void ParseJson(base::TaskRunner* blocking_task_runner,
const std::string& json,
const ParseJsonCallback& callback);
//======================= AuthenticatedRequestInterface ====================== //======================= AuthenticatedRequestInterface ======================
...@@ -249,45 +241,6 @@ class EntryActionRequest : public UrlFetchRequestBase { ...@@ -249,45 +241,6 @@ 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,24 +51,6 @@ class FakeUrlFetchRequest : public UrlFetchRequestBase { ...@@ -51,24 +51,6 @@ 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 {
...@@ -109,11 +91,7 @@ class BaseRequestsTest : public testing::Test { ...@@ -109,11 +91,7 @@ class BaseRequestsTest : public testing::Test {
}; };
TEST_F(BaseRequestsTest, ParseValidJson) { TEST_F(BaseRequestsTest, ParseValidJson) {
scoped_ptr<base::Value> json; scoped_ptr<base::Value> json(ParseJson(kValidJsonString));
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);
...@@ -125,14 +103,7 @@ TEST_F(BaseRequestsTest, ParseValidJson) { ...@@ -125,14 +103,7 @@ TEST_F(BaseRequestsTest, ParseValidJson) {
} }
TEST_F(BaseRequestsTest, ParseInvalidJson) { TEST_F(BaseRequestsTest, ParseInvalidJson) {
// Initialize with a valid pointer to verify that null is indeed assigned. EXPECT_FALSE(ParseJson(kInvalidJsonString));
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) {
...@@ -165,40 +136,4 @@ TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) { ...@@ -165,40 +136,4 @@ 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,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#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"
...@@ -23,70 +22,6 @@ namespace { ...@@ -23,70 +22,6 @@ 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
...@@ -126,17 +61,16 @@ scoped_ptr<base::DictionaryValue> CreateParentValue( ...@@ -126,17 +61,16 @@ scoped_ptr<base::DictionaryValue> CreateParentValue(
namespace drive { namespace drive {
//============================ DriveApiDataRequest =========================== //============================ DriveApiPartialFieldRequest ====================
DriveApiDataRequest::DriveApiDataRequest(RequestSender* sender, DriveApiPartialFieldRequest::DriveApiPartialFieldRequest(
const GetDataCallback& callback) RequestSender* sender) : UrlFetchRequestBase(sender) {
: GetDataRequest(sender, callback) {
} }
DriveApiDataRequest::~DriveApiDataRequest() { DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() {
} }
GURL DriveApiDataRequest::GetURL() const { GURL DriveApiPartialFieldRequest::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_);
...@@ -149,9 +83,7 @@ FilesGetRequest::FilesGetRequest( ...@@ -149,9 +83,7 @@ FilesGetRequest::FilesGetRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -168,9 +100,7 @@ FilesAuthorizeRequest::FilesAuthorizeRequest( ...@@ -168,9 +100,7 @@ FilesAuthorizeRequest::FilesAuthorizeRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -191,9 +121,7 @@ FilesInsertRequest::FilesInsertRequest( ...@@ -191,9 +121,7 @@ FilesInsertRequest::FilesInsertRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -250,9 +178,7 @@ FilesPatchRequest::FilesPatchRequest( ...@@ -250,9 +178,7 @@ FilesPatchRequest::FilesPatchRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
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) {
...@@ -320,9 +246,7 @@ FilesCopyRequest::FilesCopyRequest( ...@@ -320,9 +246,7 @@ FilesCopyRequest::FilesCopyRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -375,11 +299,7 @@ FilesListRequest::FilesListRequest( ...@@ -375,11 +299,7 @@ FilesListRequest::FilesListRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileListCallback& callback) const FileListCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileList>(sender, callback),
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());
...@@ -396,11 +316,7 @@ GURL FilesListRequest::GetURLInternal() const { ...@@ -396,11 +316,7 @@ GURL FilesListRequest::GetURLInternal() const {
FilesListNextPageRequest::FilesListNextPageRequest( FilesListNextPageRequest::FilesListNextPageRequest(
RequestSender* sender, RequestSender* sender,
const FileListCallback& callback) const FileListCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileList>(sender, callback) {
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<FileList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -445,9 +361,7 @@ FilesTrashRequest::FilesTrashRequest( ...@@ -445,9 +361,7 @@ FilesTrashRequest::FilesTrashRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const FileResourceCallback& callback) const FileResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<FileResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<FileResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -468,9 +382,7 @@ AboutGetRequest::AboutGetRequest( ...@@ -468,9 +382,7 @@ AboutGetRequest::AboutGetRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const AboutResourceCallback& callback) const AboutResourceCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<AboutResource>(sender, callback),
sender,
base::Bind(&ParseJsonAndRun<AboutResource>, callback)),
url_generator_(url_generator) { url_generator_(url_generator) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -487,11 +399,7 @@ ChangesListRequest::ChangesListRequest( ...@@ -487,11 +399,7 @@ ChangesListRequest::ChangesListRequest(
RequestSender* sender, RequestSender* sender,
const DriveApiUrlGenerator& url_generator, const DriveApiUrlGenerator& url_generator,
const ChangeListCallback& callback) const ChangeListCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<ChangeList>(sender, callback),
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),
...@@ -511,11 +419,7 @@ GURL ChangesListRequest::GetURLInternal() const { ...@@ -511,11 +419,7 @@ GURL ChangesListRequest::GetURLInternal() const {
ChangesListNextPageRequest::ChangesListNextPageRequest( ChangesListNextPageRequest::ChangesListNextPageRequest(
RequestSender* sender, RequestSender* sender,
const ChangeListCallback& callback) const ChangeListCallback& callback)
: DriveApiDataRequest( : DriveApiDataRequest<ChangeList>(sender, callback) {
sender,
base::Bind(&ParseJsonOnBlockingPoolAndRun<ChangeList>,
make_scoped_refptr(sender->blocking_task_runner()),
callback)) {
DCHECK(!callback.is_null()); DCHECK(!callback.is_null());
} }
...@@ -533,9 +437,7 @@ AppsListRequest::AppsListRequest( ...@@ -533,9 +437,7 @@ 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( : DriveApiDataRequest<AppList>(sender, callback),
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,22 +4,37 @@ ...@@ -4,22 +4,37 @@
#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 {
//============================ GetResourceEntryRequest ======================= namespace {
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 GetDataCallback& callback) const GetResourceEntryCallback& callback)
: GetDataRequest(sender, callback), : UrlFetchRequestBase(sender),
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());
} }
...@@ -30,4 +45,37 @@ GURL GetResourceEntryRequest::GetURL() const { ...@@ -30,4 +45,37 @@ 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) {
if (!entry)
error = GDATA_PARSE_ERROR;
callback_.Run(error, entry.Pass());
OnProcessURLFetchResultsComplete();
}
} // namespace google_apis } // namespace google_apis
...@@ -12,29 +12,44 @@ ...@@ -12,29 +12,44 @@
namespace google_apis { namespace google_apis {
//========================= GetResourceEntryRequest ========================== class ResourceEntry;
// 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 GetDataRequest { class GetResourceEntryRequest : public UrlFetchRequestBase {
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 GetDataCallback& callback); const GetResourceEntryCallback& 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.
const GURL& embed_origin_; 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,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#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"
...@@ -99,7 +98,7 @@ class GDataWapiRequestsTest : public testing::Test { ...@@ -99,7 +98,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<base::Value> result_data; scoped_ptr<ResourceEntry> result_data;
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -120,16 +119,14 @@ TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) { ...@@ -120,16 +119,14 @@ 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_TRUE(base::Value::Equals(expected_json.get(), result_data.get())); EXPECT_EQ("File 1.mp3", result_data->filename());
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<base::Value> result_data; scoped_ptr<ResourceEntry> 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