Commit 6f6e54e8 authored by Mark Pilgrim's avatar Mark Pilgrim Committed by Commit Bot

Migrate SpellingServiceClient to SimpleURLLoader

Bug: 844964
Change-Id: I1b47ddad2856b8a92b4f8bd6f41b1d01b8706bac
Reviewed-on: https://chromium-review.googlesource.com/1097196Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarRachel Blum <groby@chromium.org>
Commit-Queue: Mark Pilgrim <pilgrim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567326}
parent 04102856
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
...@@ -22,137 +23,38 @@ ...@@ -22,137 +23,38 @@
#include "components/spellcheck/common/spellcheck_result.h" #include "components/spellcheck/common/spellcheck_result.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/url_request/test_url_fetcher_factory.h" #include "net/http/http_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace {
// A mock URL fetcher used in the TestingSpellingServiceClient class. This class const char kSpellingServiceURL[] = "https://www.googleapis.com/rpc";
// verifies JSON-RPC requests when the SpellingServiceClient class sends them to
// the Spelling service. This class also verifies the SpellingServiceClient
// class does not either send cookies to the Spelling service or accept cookies
// from it.
class TestSpellingURLFetcher : public net::TestURLFetcher {
public:
TestSpellingURLFetcher(int id,
const GURL& url,
net::URLFetcherDelegate* d,
int version,
const std::string& sanitized_text,
const std::string& language,
int status,
const std::string& response)
: net::TestURLFetcher(0, url, d),
version_(base::StringPrintf("v%d", version)),
language_(language.empty() ? std::string("en") : language),
sanitized_text_(sanitized_text) {
set_response_code(status);
SetResponseString(response);
}
~TestSpellingURLFetcher() override {}
void SetUploadData(const std::string& upload_content_type,
const std::string& upload_content) override {
// Verify the given content type is JSON. (The Spelling service returns an
// internal server error when this content type is not JSON.)
EXPECT_EQ("application/json", upload_content_type);
// Parse the JSON to be sent to the service, and verify its parameters.
std::unique_ptr<base::DictionaryValue> value(
static_cast<base::DictionaryValue*>(
base::JSONReader::Read(upload_content,
base::JSON_ALLOW_TRAILING_COMMAS)
.release()));
ASSERT_TRUE(value.get());
std::string method;
EXPECT_TRUE(value->GetString("method", &method));
EXPECT_EQ("spelling.check", method);
std::string version;
EXPECT_TRUE(value->GetString("apiVersion", &version));
EXPECT_EQ(version_, version);
std::string sanitized_text;
EXPECT_TRUE(value->GetString("params.text", &sanitized_text));
EXPECT_EQ(sanitized_text_, sanitized_text);
std::string language;
EXPECT_TRUE(value->GetString("params.language", &language));
EXPECT_EQ(language_, language);
ASSERT_TRUE(GetExpectedCountry(language, &country_));
std::string country;
EXPECT_TRUE(value->GetString("params.originCountry", &country));
EXPECT_EQ(country_, country);
net::TestURLFetcher::SetUploadData(upload_content_type, upload_content);
}
void Start() override {
// Verify that this client does not either send cookies to the Spelling
// service or accept cookies from it.
EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES,
GetLoadFlags());
}
private:
bool GetExpectedCountry(const std::string& language, std::string* country) {
static const struct {
const char* language;
const char* country;
} kCountries[] = {
{"af", "ZAF"},
{"en", "USA"},
};
for (size_t i = 0; i < arraysize(kCountries); ++i) {
if (!language.compare(kCountries[i].language)) {
country->assign(kCountries[i].country);
return true;
}
}
return false;
}
std::string version_;
std::string language_;
std::string country_;
std::string sanitized_text_;
};
// A class derived from the SpellingServiceClient class used by the // A class derived from the SpellingServiceClient class used by the
// SpellingServiceClientTest class. This class overrides CreateURLFetcher so // SpellingServiceClientTest class. This class sets the URLLoaderFactory so
// this test can use TestSpellingURLFetcher. This class also lets tests access // tests can control requests and responses.
// the ParseResponse method.
class TestingSpellingServiceClient : public SpellingServiceClient { class TestingSpellingServiceClient : public SpellingServiceClient {
public: public:
TestingSpellingServiceClient() TestingSpellingServiceClient()
: request_type_(0), : success_(false),
response_status_(0), test_shared_loader_factory_(
success_(false), base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
fetcher_(NULL) { &test_url_loader_factory_)) {
} SetURLLoaderFactoryForTesting(test_shared_loader_factory_);
~TestingSpellingServiceClient() override {}
void SetHTTPRequest(int type,
const std::string& sanitized_text,
const std::string& language) {
request_type_ = type;
sanitized_request_text_ = sanitized_text;
request_language_ = language;
}
void SetHTTPResponse(int status, const char* data) {
response_status_ = status;
response_data_.assign(data);
} }
~TestingSpellingServiceClient() {}
void SetExpectedTextCheckResult(bool success, const char* text) { void SetExpectedTextCheckResult(bool success,
const std::string& sanitized_request_text,
const char* text) {
success_ = success; success_ = success;
sanitized_request_text_ = sanitized_request_text;
corrected_text_.assign(base::UTF8ToUTF16(text)); corrected_text_.assign(base::UTF8ToUTF16(text));
} }
void CallOnURLFetchComplete() {
ASSERT_TRUE(fetcher_);
fetcher_->delegate()->OnURLFetchComplete(fetcher_);
fetcher_ = NULL;
}
void VerifyResponse(bool success, void VerifyResponse(bool success,
const base::string16& request_text, const base::string16& request_text,
const std::vector<SpellCheckResult>& results) { const std::vector<SpellCheckResult>& results) {
...@@ -170,25 +72,16 @@ class TestingSpellingServiceClient : public SpellingServiceClient { ...@@ -170,25 +72,16 @@ class TestingSpellingServiceClient : public SpellingServiceClient {
return ParseResponse(data, &results); return ParseResponse(data, &results);
} }
private: network::TestURLLoaderFactory* test_url_loader_factory() {
std::unique_ptr<net::URLFetcher> CreateURLFetcher( return &test_url_loader_factory_;
const GURL& url,
net::NetworkTrafficAnnotationTag traffic_annotation) override {
EXPECT_EQ("https://www.googleapis.com/rpc", url.spec());
fetcher_ = new TestSpellingURLFetcher(
0, url, this, request_type_, sanitized_request_text_, request_language_,
response_status_, response_data_);
return std::unique_ptr<net::URLFetcher>(fetcher_);
} }
int request_type_; private:
std::string sanitized_request_text_;
std::string request_language_;
int response_status_;
std::string response_data_;
bool success_; bool success_;
std::string sanitized_request_text_;
base::string16 corrected_text_; base::string16 corrected_text_;
TestSpellingURLFetcher* fetcher_; // weak network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
}; };
// A test class used for testing the SpellingServiceClient class. This class // A test class used for testing the SpellingServiceClient class. This class
...@@ -204,6 +97,33 @@ class SpellingServiceClientTest : public testing::Test { ...@@ -204,6 +97,33 @@ class SpellingServiceClientTest : public testing::Test {
} }
protected: protected:
bool GetExpectedCountry(const std::string& language, std::string* country) {
static const struct {
const char* language;
const char* country;
} kCountries[] = {
{"af", "ZAF"}, {"en", "USA"},
};
for (size_t i = 0; i < arraysize(kCountries); ++i) {
if (!language.compare(kCountries[i].language)) {
country->assign(kCountries[i].country);
return true;
}
}
return false;
}
std::string GetBodyFromRequest(const network::ResourceRequest& request) {
auto body = request.request_body;
if (!body)
return std::string();
CHECK_EQ(1u, body->elements()->size());
auto& element = body->elements()->at(0);
CHECK_EQ(network::DataElement::TYPE_BYTES, element.type());
return std::string(element.bytes(), element.length());
}
content::TestBrowserThreadBundle thread_bundle_; content::TestBrowserThreadBundle thread_bundle_;
TestingSpellingServiceClient client_; TestingSpellingServiceClient client_;
TestingProfile profile_; TestingProfile profile_;
...@@ -215,121 +135,94 @@ class SpellingServiceClientTest : public testing::Test { ...@@ -215,121 +135,94 @@ class SpellingServiceClientTest : public testing::Test {
// request sent to the Spelling service as we expect. This test also verifies // request sent to the Spelling service as we expect. This test also verifies
// that it parses a JSON response from the service and calls the callback // that it parses a JSON response from the service and calls the callback
// function. To avoid sending JSON-RPC requests to the service, this test uses a // function. To avoid sending JSON-RPC requests to the service, this test uses a
// custom TestURLFecher class (TestSpellingURLFetcher) which calls // subclass of SpellingServiceClient that in turn sets the client's URL loader
// SpellingServiceClient::OnURLFetchComplete() with the parameters set by this // factory to a TestURLLoaderFactory. The client thinks it is issuing real
// test. This test also uses a custom callback function that replaces all // network requests, but in fact the responses are entirely under our control
// and no network activity takes place.
// This test also uses a custom callback function that replaces all
// misspelled words with ones suggested by the service so this test can compare // misspelled words with ones suggested by the service so this test can compare
// the corrected text with the expected results. (If there are not any // the corrected text with the expected results. (If there are not any
// misspelled words, |corrected_text| should be equal to |request_text|.) // misspelled words, |corrected_text| should be equal to |request_text|.)
TEST_F(SpellingServiceClientTest, RequestTextCheck) { TEST_F(SpellingServiceClientTest, RequestTextCheck) {
static const struct { static const struct {
const wchar_t* request_text; const wchar_t* request_text;
const char* sanitized_request_text; std::string sanitized_request_text;
SpellingServiceClient::ServiceType request_type; SpellingServiceClient::ServiceType request_type;
int response_status; net::HttpStatusCode response_status;
const char* response_data; std::string response_data;
bool success; bool success;
const char* corrected_text; const char* corrected_text;
const char* language; std::string language;
} kTests[] = { } kTests[] = {
{ {
L"", L"", "", SpellingServiceClient::SUGGEST, net::HttpStatusCode(500), "",
"", false, "", "af",
SpellingServiceClient::SUGGEST, },
500, {
"", L"chromebook", "chromebook", SpellingServiceClient::SUGGEST,
false, net::HttpStatusCode(200), "{}", true, "chromebook", "af",
"", },
"af", {
}, { L"chrombook", "chrombook", SpellingServiceClient::SUGGEST,
L"chromebook", net::HttpStatusCode(200),
"chromebook", "{\n"
SpellingServiceClient::SUGGEST, " \"result\": {\n"
200, " \"spellingCheckResponse\": {\n"
"{}", " \"misspellings\": [{\n"
true, " \"charStart\": 0,\n"
"chromebook", " \"charLength\": 9,\n"
"af", " \"suggestions\": [{ \"suggestion\": \"chromebook\" }],\n"
}, { " \"canAutoCorrect\": false\n"
L"chrombook", " }]\n"
"chrombook", " }\n"
SpellingServiceClient::SUGGEST, " }\n"
200, "}",
"{\n" true, "chromebook", "af",
" \"result\": {\n" },
" \"spellingCheckResponse\": {\n" {
" \"misspellings\": [{\n" L"", "", SpellingServiceClient::SPELLCHECK, net::HttpStatusCode(500),
" \"charStart\": 0,\n" "", false, "", "en",
" \"charLength\": 9,\n" },
" \"suggestions\": [{ \"suggestion\": \"chromebook\" }],\n" {
" \"canAutoCorrect\": false\n" L"I have been to USA.", "I have been to USA.",
" }]\n" SpellingServiceClient::SPELLCHECK, net::HttpStatusCode(200), "{}",
" }\n" true, "I have been to USA.", "en",
" }\n" },
"}", {
true, L"I have bean to USA.", "I have bean to USA.",
"chromebook", SpellingServiceClient::SPELLCHECK, net::HttpStatusCode(200),
"af", "{\n"
}, { " \"result\": {\n"
L"", " \"spellingCheckResponse\": {\n"
"", " \"misspellings\": [{\n"
SpellingServiceClient::SPELLCHECK, " \"charStart\": 7,\n"
500, " \"charLength\": 4,\n"
"", " \"suggestions\": [{ \"suggestion\": \"been\" }],\n"
false, " \"canAutoCorrect\": false\n"
"", " }]\n"
"en", " }\n"
}, { " }\n"
L"I have been to USA.", "}",
"I have been to USA.", true, "I have been to USA.", "en",
SpellingServiceClient::SPELLCHECK, },
200, {
"{}", L"I\x2019mattheIn'n'Out.", "I'mattheIn'n'Out.",
true, SpellingServiceClient::SPELLCHECK, net::HttpStatusCode(200),
"I have been to USA.", "{\n"
"en", " \"result\": {\n"
}, { " \"spellingCheckResponse\": {\n"
L"I have bean to USA.", " \"misspellings\": [{\n"
"I have bean to USA.", " \"charStart\": 0,\n"
SpellingServiceClient::SPELLCHECK, " \"charLength\": 16,\n"
200, " \"suggestions\":"
"{\n" " [{ \"suggestion\": \"I'm at the In'N'Out\" }],\n"
" \"result\": {\n" " \"canAutoCorrect\": false\n"
" \"spellingCheckResponse\": {\n" " }]\n"
" \"misspellings\": [{\n" " }\n"
" \"charStart\": 7,\n" " }\n"
" \"charLength\": 4,\n" "}",
" \"suggestions\": [{ \"suggestion\": \"been\" }],\n" true, "I'm at the In'N'Out.", "en",
" \"canAutoCorrect\": false\n" },
" }]\n"
" }\n"
" }\n"
"}",
true,
"I have been to USA.",
"en",
}, {
L"I\x2019mattheIn'n'Out.",
"I'mattheIn'n'Out.",
SpellingServiceClient::SPELLCHECK,
200,
"{\n"
" \"result\": {\n"
" \"spellingCheckResponse\": {\n"
" \"misspellings\": [{\n"
" \"charStart\": 0,\n"
" \"charLength\": 16,\n"
" \"suggestions\":"
" [{ \"suggestion\": \"I'm at the In'N'Out\" }],\n"
" \"canAutoCorrect\": false\n"
" }]\n"
" }\n"
" }\n"
"}",
true,
"I'm at the In'N'Out.",
"en",
},
}; };
PrefService* pref = profile_.GetPrefs(); PrefService* pref = profile_.GetPrefs();
...@@ -337,11 +230,29 @@ TEST_F(SpellingServiceClientTest, RequestTextCheck) { ...@@ -337,11 +230,29 @@ TEST_F(SpellingServiceClientTest, RequestTextCheck) {
pref->SetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService, true); pref->SetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService, true);
for (size_t i = 0; i < arraysize(kTests); ++i) { for (size_t i = 0; i < arraysize(kTests); ++i) {
client_.SetHTTPRequest(kTests[i].request_type, client_.test_url_loader_factory()->ClearResponses();
kTests[i].sanitized_request_text, net::HttpStatusCode http_status = kTests[i].response_status;
kTests[i].language); network::ResourceResponseHead head;
client_.SetHTTPResponse(kTests[i].response_status, kTests[i].response_data); std::string headers(base::StringPrintf(
"HTTP/1.1 %d %s\nContent-type: application/json\n\n",
static_cast<int>(http_status), net::GetHttpReasonPhrase(http_status)));
head.headers = new net::HttpResponseHeaders(
net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
head.mime_type = "application/json";
network::URLLoaderCompletionStatus status;
status.decoded_body_length = kTests[i].response_data.size();
client_.test_url_loader_factory()->AddResponse(
GURL(kSpellingServiceURL), head, kTests[i].response_data, status);
net::HttpRequestHeaders intercepted_headers;
std::string intercepted_body;
client_.test_url_loader_factory()->SetInterceptor(
base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
intercepted_headers = request.headers;
intercepted_body = GetBodyFromRequest(request);
}));
client_.SetExpectedTextCheckResult(kTests[i].success, client_.SetExpectedTextCheckResult(kTests[i].success,
kTests[i].sanitized_request_text,
kTests[i].corrected_text); kTests[i].corrected_text);
base::ListValue dictionary; base::ListValue dictionary;
dictionary.AppendString(kTests[i].language); dictionary.AppendString(kTests[i].language);
...@@ -352,7 +263,41 @@ TEST_F(SpellingServiceClientTest, RequestTextCheck) { ...@@ -352,7 +263,41 @@ TEST_F(SpellingServiceClientTest, RequestTextCheck) {
base::WideToUTF16(kTests[i].request_text), base::WideToUTF16(kTests[i].request_text),
base::BindOnce(&SpellingServiceClientTest::OnTextCheckComplete, base::BindOnce(&SpellingServiceClientTest::OnTextCheckComplete,
base::Unretained(this), 0)); base::Unretained(this), 0));
client_.CallOnURLFetchComplete(); thread_bundle_.RunUntilIdle();
// Verify the request content type was JSON. (The Spelling service returns
// an internal server error when this content type is not JSON.)
std::string request_content_type;
ASSERT_TRUE(intercepted_headers.GetHeader(
net::HttpRequestHeaders::kContentType, &request_content_type));
EXPECT_EQ("application/json", request_content_type);
// Parse the JSON sent to the service, and verify its parameters.
std::unique_ptr<base::DictionaryValue> value(
static_cast<base::DictionaryValue*>(
base::JSONReader::Read(intercepted_body,
base::JSON_ALLOW_TRAILING_COMMAS)
.release()));
ASSERT_TRUE(value.get());
std::string method;
EXPECT_TRUE(value->GetString("method", &method));
EXPECT_EQ("spelling.check", method);
std::string version;
EXPECT_TRUE(value->GetString("apiVersion", &version));
EXPECT_EQ(base::StringPrintf("v%d", kTests[i].request_type), version);
std::string sanitized_text;
EXPECT_TRUE(value->GetString("params.text", &sanitized_text));
EXPECT_EQ(kTests[i].sanitized_request_text, sanitized_text);
std::string language;
EXPECT_TRUE(value->GetString("params.language", &language));
std::string expected_language =
kTests[i].language.empty() ? std::string("en") : kTests[i].language;
EXPECT_EQ(expected_language, language);
std::string expected_country;
ASSERT_TRUE(GetExpectedCountry(language, &expected_country));
std::string country;
EXPECT_TRUE(value->GetString("params.originCountry", &country));
EXPECT_EQ(expected_country, country);
} }
} }
......
...@@ -37,6 +37,7 @@ source_set("browser") { ...@@ -37,6 +37,7 @@ source_set("browser") {
"//content/public/common", "//content/public/common",
"//google_apis", "//google_apis",
"//net", "//net",
"//services/network/public/cpp",
] ]
if (is_android) { if (is_android) {
...@@ -60,6 +61,8 @@ source_set("unit_tests") { ...@@ -60,6 +61,8 @@ source_set("unit_tests") {
"//content/test:test_support", "//content/test:test_support",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//net:test_support", "//net:test_support",
"//services/network:test_support",
"//services/network/public/cpp",
"//testing/gtest", "//testing/gtest",
] ]
} }
...@@ -10,4 +10,6 @@ include_rules = [ ...@@ -10,4 +10,6 @@ include_rules = [
"+jni", "+jni",
"+mojo/public/cpp/bindings", "+mojo/public/cpp/bindings",
"+net", "+net",
"+services/network/public/cpp",
"+services/network/test",
] ]
...@@ -28,7 +28,9 @@ ...@@ -28,7 +28,9 @@
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "google_apis/google_api_keys.h" #include "google_apis/google_api_keys.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/url_request/url_fetcher.h" #include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace { namespace {
...@@ -48,9 +50,9 @@ const char* const kValidLanguages[] = {"en", "es", "fi", "da"}; ...@@ -48,9 +50,9 @@ const char* const kValidLanguages[] = {"en", "es", "fi", "da"};
} // namespace } // namespace
SpellingServiceClient::SpellingServiceClient() {} SpellingServiceClient::SpellingServiceClient() = default;
SpellingServiceClient::~SpellingServiceClient() {} SpellingServiceClient::~SpellingServiceClient() = default;
bool SpellingServiceClient::RequestTextCheck( bool SpellingServiceClient::RequestTextCheck(
content::BrowserContext* context, content::BrowserContext* context,
...@@ -62,7 +64,6 @@ bool SpellingServiceClient::RequestTextCheck( ...@@ -62,7 +64,6 @@ bool SpellingServiceClient::RequestTextCheck(
std::move(callback).Run(false, text, std::vector<SpellCheckResult>()); std::move(callback).Run(false, text, std::vector<SpellCheckResult>());
return false; return false;
} }
const PrefService* pref = user_prefs::UserPrefs::Get(context); const PrefService* pref = user_prefs::UserPrefs::Get(context);
DCHECK(pref); DCHECK(pref);
...@@ -138,19 +139,32 @@ bool SpellingServiceClient::RequestTextCheck( ...@@ -138,19 +139,32 @@ bool SpellingServiceClient::RequestTextCheck(
} }
})"); })");
net::URLFetcher* fetcher = auto resource_request = std::make_unique<network::ResourceRequest>();
CreateURLFetcher(url, traffic_annotation).release(); resource_request->url = url;
data_use_measurement::DataUseUserData::AttachToFetcher( resource_request->load_flags =
fetcher, data_use_measurement::DataUseUserData::SPELL_CHECKER); net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
fetcher->SetRequestContext( resource_request->method = "POST";
content::BrowserContext::GetDefaultStoragePartition(context) std::unique_ptr<network::SimpleURLLoader> simple_url_loader =
->GetURLRequestContext()); network::SimpleURLLoader::Create(std::move(resource_request),
fetcher->SetUploadData("application/json", request); traffic_annotation);
fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | simple_url_loader->AttachStringForUpload(request, "application/json");
net::LOAD_DO_NOT_SAVE_COOKIES); auto it = spellcheck_loaders_.insert(
spellcheck_fetchers_[fetcher] = std::make_unique<TextCheckCallbackData>( spellcheck_loaders_.begin(),
base::WrapUnique(fetcher), std::move(callback), text); std::make_unique<TextCheckCallbackData>(std::move(simple_url_loader),
fetcher->Start(); std::move(callback), text));
network::SimpleURLLoader* loader = it->get()->simple_url_loader.get();
auto url_loader_factory =
url_loader_factory_for_testing_
? url_loader_factory_for_testing_
: content::BrowserContext::GetDefaultStoragePartition(context)
->GetURLLoaderFactoryForBrowserProcess();
// TODO(https://crbug.com/808498): Re-add data use measurement once
// SimpleURLLoader supports it.
// ID=data_use_measurement::DataUseUserData::SPELL_CHECKER
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory.get(),
base::BindOnce(&SpellingServiceClient::OnSimpleLoaderComplete,
base::Unretained(this), std::move(it)));
return true; return true;
} }
...@@ -279,35 +293,30 @@ bool SpellingServiceClient::ParseResponse( ...@@ -279,35 +293,30 @@ bool SpellingServiceClient::ParseResponse(
} }
SpellingServiceClient::TextCheckCallbackData::TextCheckCallbackData( SpellingServiceClient::TextCheckCallbackData::TextCheckCallbackData(
std::unique_ptr<net::URLFetcher> fetcher, std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
TextCheckCompleteCallback callback, TextCheckCompleteCallback callback,
base::string16 text) base::string16 text)
: fetcher(std::move(fetcher)), callback(std::move(callback)), text(text) {} : simple_url_loader(std::move(simple_url_loader)),
callback(std::move(callback)),
text(text) {}
SpellingServiceClient::TextCheckCallbackData::~TextCheckCallbackData() {} SpellingServiceClient::TextCheckCallbackData::~TextCheckCallbackData() {}
void SpellingServiceClient::OnURLFetchComplete(const net::URLFetcher* source) { void SpellingServiceClient::OnSimpleLoaderComplete(
DCHECK(base::ContainsKey(spellcheck_fetchers_, source)); SpellCheckLoaderList::iterator it,
std::unique_ptr<TextCheckCallbackData> callback_data = std::unique_ptr<std::string> response_body) {
std::move(spellcheck_fetchers_[source]); TextCheckCompleteCallback callback = std::move(it->get()->callback);
spellcheck_fetchers_.erase(source); base::string16 text = it->get()->text;
bool success = false; bool success = false;
std::vector<SpellCheckResult> results; std::vector<SpellCheckResult> results;
if (source->GetResponseCode() / 100 == 2) { if (response_body)
std::string data; success = ParseResponse(*response_body, &results);
source->GetResponseAsString(&data); spellcheck_loaders_.erase(it);
success = ParseResponse(data, &results); std::move(callback).Run(success, text, results);
}
// The callback may release the last (transitive) dependency on |this|. It
// MUST be the last function called.
std::move(callback_data->callback).Run(success, callback_data->text, results);
} }
std::unique_ptr<net::URLFetcher> SpellingServiceClient::CreateURLFetcher( void SpellingServiceClient::SetURLLoaderFactoryForTesting(
const GURL& url, scoped_refptr<network::SharedURLLoaderFactory>
net::NetworkTrafficAnnotationTag traffic_annotation) { url_loader_factory_for_testing) {
return net::URLFetcher::Create(url, net::URLFetcher::POST, this, url_loader_factory_for_testing_ = std::move(url_loader_factory_for_testing);
traffic_annotation);
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_ #ifndef COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
#define COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_ #define COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
#include <map> #include <list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -14,18 +14,17 @@ ...@@ -14,18 +14,17 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher_delegate.h"
class GURL;
struct SpellCheckResult; struct SpellCheckResult;
namespace content { namespace content {
class BrowserContext; class BrowserContext;
} }
namespace net { namespace network {
class URLFetcher; class SharedURLLoaderFactory;
} // namespace net class SimpleURLLoader;
} // namespace network
// A class that encapsulates a JSON-RPC call to the Spelling service to check // A class that encapsulates a JSON-RPC call to the Spelling service to check
// text there. This class creates a JSON-RPC request, sends the request to the // text there. This class creates a JSON-RPC request, sends the request to the
...@@ -57,7 +56,7 @@ class URLFetcher; ...@@ -57,7 +56,7 @@ class URLFetcher;
// std::unique_ptr<SpellingServiceClient> client_; // std::unique_ptr<SpellingServiceClient> client_;
// }; // };
// //
class SpellingServiceClient : public net::URLFetcherDelegate { class SpellingServiceClient {
public: public:
// Service types provided by the Spelling service. The Spelling service // Service types provided by the Spelling service. The Spelling service
// consists of a couple of backends: // consists of a couple of backends:
...@@ -76,7 +75,7 @@ class SpellingServiceClient : public net::URLFetcherDelegate { ...@@ -76,7 +75,7 @@ class SpellingServiceClient : public net::URLFetcherDelegate {
TextCheckCompleteCallback; TextCheckCompleteCallback;
SpellingServiceClient(); SpellingServiceClient();
~SpellingServiceClient() override; ~SpellingServiceClient();
// Sends a text-check request to the Spelling service. When we send a request // Sends a text-check request to the Spelling service. When we send a request
// to the Spelling service successfully, this function returns true. (This // to the Spelling service successfully, this function returns true. (This
...@@ -90,6 +89,11 @@ class SpellingServiceClient : public net::URLFetcherDelegate { ...@@ -90,6 +89,11 @@ class SpellingServiceClient : public net::URLFetcherDelegate {
// Returns whether the specified service is available for the given context. // Returns whether the specified service is available for the given context.
static bool IsAvailable(content::BrowserContext* context, ServiceType type); static bool IsAvailable(content::BrowserContext* context, ServiceType type);
// Set the URL loader factory for tests.
void SetURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory>
url_loader_factory_for_testing);
protected: protected:
// Parses a JSON-RPC response from the Spelling service. // Parses a JSON-RPC response from the Spelling service.
bool ParseResponse(const std::string& data, bool ParseResponse(const std::string& data,
...@@ -98,13 +102,14 @@ class SpellingServiceClient : public net::URLFetcherDelegate { ...@@ -98,13 +102,14 @@ class SpellingServiceClient : public net::URLFetcherDelegate {
private: private:
struct TextCheckCallbackData { struct TextCheckCallbackData {
public: public:
TextCheckCallbackData(std::unique_ptr<net::URLFetcher> fetcher, TextCheckCallbackData(
TextCheckCompleteCallback callback, std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
base::string16 text); TextCheckCompleteCallback callback,
base::string16 text);
~TextCheckCallbackData(); ~TextCheckCallbackData();
// The fetcher used. // The URL loader used.
std::unique_ptr<net::URLFetcher> fetcher; std::unique_ptr<network::SimpleURLLoader> simple_url_loader;
// The callback function to be called when we receive a response from the // The callback function to be called when we receive a response from the
// Spelling service and parse it. // Spelling service and parse it.
...@@ -117,19 +122,18 @@ class SpellingServiceClient : public net::URLFetcherDelegate { ...@@ -117,19 +122,18 @@ class SpellingServiceClient : public net::URLFetcherDelegate {
DISALLOW_COPY_AND_ASSIGN(TextCheckCallbackData); DISALLOW_COPY_AND_ASSIGN(TextCheckCallbackData);
}; };
// net::URLFetcherDelegate implementation. using SpellCheckLoaderList =
void OnURLFetchComplete(const net::URLFetcher* source) override; std::list<std::unique_ptr<TextCheckCallbackData>>;
void OnSimpleLoaderComplete(SpellCheckLoaderList::iterator it,
std::unique_ptr<std::string> response_body);
// Creates a URLFetcher object used for sending a JSON-RPC request. This // List of loaders in use.
// function is overridden by unit tests to prevent them from actually sending SpellCheckLoaderList spellcheck_loaders_;
// requests to the Spelling service.
virtual std::unique_ptr<net::URLFetcher> CreateURLFetcher(
const GURL& url,
net::NetworkTrafficAnnotationTag traffic_annotation);
// The URLFetcher object used for sending a JSON-RPC request. // URL loader factory to use for fake network requests during testing.
std::map<const net::URLFetcher*, std::unique_ptr<TextCheckCallbackData>> scoped_refptr<network::SharedURLLoaderFactory>
spellcheck_fetchers_; url_loader_factory_for_testing_;
}; };
#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_ #endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
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