Commit d8235928 authored by Maks Orlovich's avatar Maks Orlovich Committed by Commit Bot

S13n: Port ChromeOmniboxNavigationObserver to SimpleURLLoader

URLFetcher will stop working with advent of Network Service, and
SimpleURLLoader is the replacement API for most clients.


Bug: 840378
Cq-Include-Trybots: luci.chromium.try:linux_mojo
Change-Id: Ie318335f2d3a21cac1042862fd6a49e62cc931a4
Reviewed-on: https://chromium-review.googlesource.com/1124771
Commit-Queue: Maks Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575900}
parent c80a1864
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h" #include "services/network/public/cpp/resource_request.h"
#include "net/url_request/url_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"
#include "url/url_constants.h" #include "url/url_constants.h"
...@@ -81,11 +82,10 @@ ChromeOmniboxNavigationObserver::ChromeOmniboxNavigationObserver( ...@@ -81,11 +82,10 @@ ChromeOmniboxNavigationObserver::ChromeOmniboxNavigationObserver(
alternate_nav_match_(alternate_nav_match), alternate_nav_match_(alternate_nav_match),
template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)),
shortcuts_backend_(ShortcutsBackendFactory::GetForProfile(profile)), shortcuts_backend_(ShortcutsBackendFactory::GetForProfile(profile)),
request_context_(nullptr),
load_state_(LOAD_NOT_SEEN), load_state_(LOAD_NOT_SEEN),
fetch_state_(FETCH_NOT_COMPLETE) { fetch_state_(FETCH_NOT_COMPLETE) {
if (alternate_nav_match_.destination_url.is_valid()) if (alternate_nav_match_.destination_url.is_valid())
CreateFetcher(alternate_nav_match_.destination_url); CreateLoader(alternate_nav_match_.destination_url);
// We need to start by listening to AllSources, since we don't know which tab // We need to start by listening to AllSources, since we don't know which tab
// the navigation might occur in. // the navigation might occur in.
...@@ -117,6 +117,11 @@ void ChromeOmniboxNavigationObserver::On404() { ...@@ -117,6 +117,11 @@ void ChromeOmniboxNavigationObserver::On404() {
template_url_service_->Remove(template_url); template_url_service_->Remove(template_url);
} }
void ChromeOmniboxNavigationObserver::SetURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> testing_loader_factory) {
loader_factory_for_testing_ = std::move(testing_loader_factory);
}
void ChromeOmniboxNavigationObserver::CreateAlternateNavInfoBar() { void ChromeOmniboxNavigationObserver::CreateAlternateNavInfoBar() {
AlternateNavInfoBarDelegate::Create( AlternateNavInfoBarDelegate::Create(
web_contents(), text_, alternate_nav_match_, match_.destination_url); web_contents(), text_, alternate_nav_match_, match_.destination_url);
...@@ -169,13 +174,22 @@ void ChromeOmniboxNavigationObserver::Observe( ...@@ -169,13 +174,22 @@ void ChromeOmniboxNavigationObserver::Observe(
load_state_ = LOAD_PENDING; load_state_ = LOAD_PENDING;
WebContentsObserver::Observe(web_contents); WebContentsObserver::Observe(web_contents);
// Start the alternate nav fetcher if need be. // Start the alternate nav loader if need be.
if (fetcher_) { if (loader_) {
request_context_ = content::BrowserContext::GetDefaultStoragePartition( network::mojom::URLLoaderFactory* loader_factory = nullptr;
if (loader_factory_for_testing_) {
loader_factory = loader_factory_for_testing_.get();
} else {
loader_factory = content::BrowserContext::GetDefaultStoragePartition(
controller->GetBrowserContext()) controller->GetBrowserContext())
->GetURLRequestContext(); ->GetURLLoaderFactoryForBrowserProcess()
fetcher_->SetRequestContext(request_context_); .get();
fetcher_->Start(); }
loader_->DownloadToString(
loader_factory,
base::BindOnce(&ChromeOmniboxNavigationObserver::OnURLLoadComplete,
base::Unretained(this)),
1u /* max_body_size */);
} }
} }
...@@ -196,7 +210,7 @@ void ChromeOmniboxNavigationObserver::NavigationEntryCommitted( ...@@ -196,7 +210,7 @@ void ChromeOmniboxNavigationObserver::NavigationEntryCommitted(
OnSuccessfulNavigation(); OnSuccessfulNavigation();
if (load_details.http_status_code == 404) if (load_details.http_status_code == 404)
On404(); On404();
if (!fetcher_ || (fetch_state_ != FETCH_NOT_COMPLETE)) if (!loader_ || (fetch_state_ != FETCH_NOT_COMPLETE))
OnAllLoadingFinished(); // deletes |this|! OnAllLoadingFinished(); // deletes |this|!
} }
...@@ -204,15 +218,12 @@ void ChromeOmniboxNavigationObserver::WebContentsDestroyed() { ...@@ -204,15 +218,12 @@ void ChromeOmniboxNavigationObserver::WebContentsDestroyed() {
delete this; delete this;
} }
void ChromeOmniboxNavigationObserver::OnURLFetchComplete( void ChromeOmniboxNavigationObserver::OnURLRedirect(
const net::URLFetcher* source) { const net::RedirectInfo& redirect_info,
DCHECK_EQ(fetcher_.get(), source); const network::ResourceResponseHead& response_head,
const net::URLRequestStatus& status = source->GetStatus(); std::vector<std::string>* to_be_removed_headers) {
int response_code = source->GetResponseCode(); bool valid_redirect = IsValidNavigation(alternate_nav_match_.destination_url,
bool valid_redirect = redirect_info.new_url);
(status.status() == net::URLRequestStatus::CANCELED) &&
((response_code / 100) == 3) &&
IsValidNavigation(alternate_nav_match_.destination_url, source->GetURL());
// If this is a valid redirect (not hijacked), and the redirect is from // If this is a valid redirect (not hijacked), and the redirect is from
// http->https (no other changes), then follow it instead of assuming the // http->https (no other changes), then follow it instead of assuming the
// destination is valid. This fixes several cases when the infobar appears // destination is valid. This fixes several cases when the infobar appears
...@@ -229,17 +240,41 @@ void ChromeOmniboxNavigationObserver::OnURLFetchComplete( ...@@ -229,17 +240,41 @@ void ChromeOmniboxNavigationObserver::OnURLFetchComplete(
// requests for local sites. // requests for local sites.
if (valid_redirect && if (valid_redirect &&
OnlyChangeIsFromHTTPToHTTPS(alternate_nav_match_.destination_url, OnlyChangeIsFromHTTPToHTTPS(alternate_nav_match_.destination_url,
source->GetURL())) { redirect_info.new_url)) {
CreateFetcher(source->GetURL());
fetcher_->SetRequestContext(request_context_);
fetcher_->Start();
return; return;
} }
fetch_state_ =
((status.is_success() && ResponseCodeIndicatesSuccess(response_code)) || // Otherwise report results based on whether the redirect itself is valid.
valid_redirect) // OnDoneWithURL() will also stop the redirect from being followed since it
? FETCH_SUCCEEDED // destroys |*loader_|.
: FETCH_FAILED; //
// We stop-on-redirect here for a couple of reasons:
// * Sites with lots of redirects, especially through slow machines, take time
// to follow the redirects. This delays the appearance of the infobar,
// sometimes by several seconds, which feels really broken.
// * Some servers behind redirects respond to HEAD with an error and GET with
// a valid response, in violation of the HTTP spec. Stop-on-redirects
// reduces the number of cases where this error makes us believe there was
// no server.
OnDoneWithURL(valid_redirect);
}
void ChromeOmniboxNavigationObserver::OnURLLoadComplete(
std::unique_ptr<std::string> body) {
int response_code = -1;
if (loader_->ResponseInfo() && loader_->ResponseInfo()->headers)
response_code = loader_->ResponseInfo()->headers->response_code();
// We may see ERR_INSUFFICIENT_RESOURCES here even if everything is workable
// if the server includes a body in response to a HEAD, as a size limit was
// set while fetching.
bool fetch_likely_ok = loader_->NetError() == net::OK ||
loader_->NetError() == net::ERR_INSUFFICIENT_RESOURCES;
OnDoneWithURL(fetch_likely_ok && ResponseCodeIndicatesSuccess(response_code));
}
void ChromeOmniboxNavigationObserver::OnDoneWithURL(bool success) {
loader_ = nullptr;
fetch_state_ = success ? FETCH_SUCCEEDED : FETCH_FAILED;
if (load_state_ == LOAD_COMMITTED) if (load_state_ == LOAD_COMMITTED)
OnAllLoadingFinished(); // deletes |this|! OnAllLoadingFinished(); // deletes |this|!
} }
...@@ -250,7 +285,7 @@ void ChromeOmniboxNavigationObserver::OnAllLoadingFinished() { ...@@ -250,7 +285,7 @@ void ChromeOmniboxNavigationObserver::OnAllLoadingFinished() {
delete this; delete this;
} }
void ChromeOmniboxNavigationObserver::CreateFetcher( void ChromeOmniboxNavigationObserver::CreateLoader(
const GURL& destination_url) { const GURL& destination_url) {
net::NetworkTrafficAnnotationTag traffic_annotation = net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("omnibox_navigation_observer", R"( net::DefineNetworkTrafficAnnotation("omnibox_navigation_observer", R"(
...@@ -282,17 +317,13 @@ void ChromeOmniboxNavigationObserver::CreateFetcher( ...@@ -282,17 +317,13 @@ void ChromeOmniboxNavigationObserver::CreateFetcher(
"this. More fine-grained policies are requested to be " "this. More fine-grained policies are requested to be "
"implemented (crbug.com/81226)." "implemented (crbug.com/81226)."
})"); })");
fetcher_ = net::URLFetcher::Create(destination_url, net::URLFetcher::HEAD, auto request = std::make_unique<network::ResourceRequest>();
this, traffic_annotation); request->url = destination_url;
fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); request->method = "HEAD";
// We stop-on-redirect for a couple of reasons: request->load_flags = net::LOAD_DO_NOT_SAVE_COOKIES;
// * Sites with lots of redirects, especially through slow machines, take time loader_ =
// to follow the redirects. This delays the appearance of the infobar, network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
// sometimes by several seconds, which feels really broken. loader_->SetAllowHttpErrorResults(true);
// * Some servers behind redirects respond to HEAD with an error and GET with loader_->SetOnRedirectCallback(base::BindRepeating(
// a valid response, in violation of the HTTP spec. Stop-on-redirects &ChromeOmniboxNavigationObserver::OnURLRedirect, base::Unretained(this)));
// reduces the number of cases where this error makes us believe there was
// no server.
// We do allow a certain kind of redirect; see code in OnURLFetchComplete().
fetcher_->SetStopOnRedirect(true);
} }
...@@ -23,9 +23,9 @@ class Profile; ...@@ -23,9 +23,9 @@ class Profile;
class ShortcutsBackend; class ShortcutsBackend;
class TemplateURLService; class TemplateURLService;
namespace net { namespace network {
class URLFetcher; class SharedURLLoaderFactory;
class URLRequestContextGetter; class SimpleURLLoader;
} }
// Monitors omnibox navigations in order to trigger behaviors that depend on // Monitors omnibox navigations in order to trigger behaviors that depend on
...@@ -46,8 +46,7 @@ class URLRequestContextGetter; ...@@ -46,8 +46,7 @@ class URLRequestContextGetter;
// about the memory management of this object. // about the memory management of this object.
class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver, class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver,
public content::NotificationObserver, public content::NotificationObserver,
public content::WebContentsObserver, public content::WebContentsObserver {
public net::URLFetcherDelegate {
public: public:
enum LoadState { enum LoadState {
LOAD_NOT_SEEN, LOAD_NOT_SEEN,
...@@ -74,6 +73,11 @@ class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver, ...@@ -74,6 +73,11 @@ class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver,
// the broken engine again. // the broken engine again.
void On404(); void On404();
// Test-only method to override how loading happens. Normally this is
// extracted from the profile passed to the constructor.
void SetURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> testing_loader_factory);
protected: protected:
// Creates/displays the alternate nav infobar. Overridden in tests. // Creates/displays the alternate nav infobar. Overridden in tests.
virtual void CreateAlternateNavInfoBar(); virtual void CreateAlternateNavInfoBar();
...@@ -105,27 +109,32 @@ class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver, ...@@ -105,27 +109,32 @@ class ChromeOmniboxNavigationObserver : public OmniboxNavigationObserver,
const content::LoadCommittedDetails& load_details) override; const content::LoadCommittedDetails& load_details) override;
void WebContentsDestroyed() override; void WebContentsDestroyed() override;
// net::URLFetcherDelegate: // Used as callbacks from |loader_|.
void OnURLFetchComplete(const net::URLFetcher* source) override; void OnURLLoadComplete(std::unique_ptr<std::string> body);
// See SimpleURLLoader::OnRedirectCallback for info on the signature.
void OnURLRedirect(const net::RedirectInfo& redirect_info,
const network::ResourceResponseHead& response_head,
std::vector<std::string>* to_be_removed_headers);
// Called from either OnURLLoadComplete or OnURLRedirect.
void OnDoneWithURL(bool success);
// Once the load has committed and any URL fetch has completed, this displays // Once the load has committed and any URL fetch has completed, this displays
// the alternate nav infobar if necessary, and deletes |this|. // the alternate nav infobar if necessary, and deletes |this|.
void OnAllLoadingFinished(); void OnAllLoadingFinished();
// Creates a URL fetcher for |destination_url| and stores it in |fetcher_|. // Creates a URL loader for |destination_url| and stores it in |loader_|.
// Does not start the fetcher. // Does not start the loader.
void CreateFetcher(const GURL& destination_url); void CreateLoader(const GURL& destination_url);
const base::string16 text_; const base::string16 text_;
const AutocompleteMatch match_; const AutocompleteMatch match_;
const AutocompleteMatch alternate_nav_match_; const AutocompleteMatch alternate_nav_match_;
TemplateURLService* template_url_service_; TemplateURLService* template_url_service_;
scoped_refptr<ShortcutsBackend> shortcuts_backend_; // NULL in incognito. scoped_refptr<ShortcutsBackend> shortcuts_backend_; // NULL in incognito.
std::unique_ptr<net::URLFetcher> fetcher_; std::unique_ptr<network::SimpleURLLoader> loader_;
// The request context used by |fetcher_|. It's necessary to keep a reference scoped_refptr<network::SharedURLLoaderFactory> loader_factory_for_testing_;
// to this because sometimes we need to create a follow-up fetcher with the
// same context and URLFetcher does not have a way to get the context out.
net::URLRequestContextGetter* request_context_;
LoadState load_state_; LoadState load_state_;
FetchState fetch_state_; FetchState fetch_state_;
......
...@@ -34,13 +34,15 @@ void TestURLLoaderFactory::AddResponse(const GURL& url, ...@@ -34,13 +34,15 @@ void TestURLLoaderFactory::AddResponse(const GURL& url,
const ResourceResponseHead& head, const ResourceResponseHead& head,
const std::string& content, const std::string& content,
const URLLoaderCompletionStatus& status, const URLLoaderCompletionStatus& status,
const Redirects& redirects) { const Redirects& redirects,
ResponseProduceFlags flags) {
Response response; Response response;
response.url = url; response.url = url;
response.redirects = redirects; response.redirects = redirects;
response.head = head; response.head = head;
response.content = content; response.content = content;
response.status = status; response.status = status;
response.flags = flags;
responses_[url] = response; responses_[url] = response;
for (auto it = pending_requests_.begin(); it != pending_requests_.end();) { for (auto it = pending_requests_.begin(); it != pending_requests_.end();) {
...@@ -125,7 +127,7 @@ bool TestURLLoaderFactory::CreateLoaderAndStartInternal( ...@@ -125,7 +127,7 @@ bool TestURLLoaderFactory::CreateLoaderAndStartInternal(
return false; return false;
SimulateResponse(client, it->second.redirects, it->second.head, SimulateResponse(client, it->second.redirects, it->second.head,
it->second.content, it->second.status); it->second.content, it->second.status, it->second.flags);
return true; return true;
} }
...@@ -134,7 +136,7 @@ bool TestURLLoaderFactory::SimulateResponseForPendingRequest( ...@@ -134,7 +136,7 @@ bool TestURLLoaderFactory::SimulateResponseForPendingRequest(
const network::URLLoaderCompletionStatus& completion_status, const network::URLLoaderCompletionStatus& completion_status,
const ResourceResponseHead& response_head, const ResourceResponseHead& response_head,
const std::string& content, const std::string& content,
SimulateResponseFlags flags) { ResponseMatchFlags flags) {
if (pending_requests_.empty()) if (pending_requests_.empty())
return false; return false;
...@@ -172,7 +174,7 @@ bool TestURLLoaderFactory::SimulateResponseForPendingRequest( ...@@ -172,7 +174,7 @@ bool TestURLLoaderFactory::SimulateResponseForPendingRequest(
status.decoded_body_length = content.size(); status.decoded_body_length = content.size();
SimulateResponse(request.client.get(), TestURLLoaderFactory::Redirects(), SimulateResponse(request.client.get(), TestURLLoaderFactory::Redirects(),
response_head, content, status); response_head, content, status, kResponseDefault);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
return true; return true;
...@@ -186,7 +188,7 @@ void TestURLLoaderFactory::SimulateResponseWithoutRemovingFromPendingList( ...@@ -186,7 +188,7 @@ void TestURLLoaderFactory::SimulateResponseWithoutRemovingFromPendingList(
URLLoaderCompletionStatus status(completion_status); URLLoaderCompletionStatus status(completion_status);
status.decoded_body_length = content.size(); status.decoded_body_length = content.size();
SimulateResponse(request->client.get(), TestURLLoaderFactory::Redirects(), SimulateResponse(request->client.get(), TestURLLoaderFactory::Redirects(),
head, content, status); head, content, status, kResponseDefault);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
...@@ -205,10 +207,14 @@ void TestURLLoaderFactory::SimulateResponse( ...@@ -205,10 +207,14 @@ void TestURLLoaderFactory::SimulateResponse(
TestURLLoaderFactory::Redirects redirects, TestURLLoaderFactory::Redirects redirects,
ResourceResponseHead head, ResourceResponseHead head,
std::string content, std::string content,
URLLoaderCompletionStatus status) { URLLoaderCompletionStatus status,
ResponseProduceFlags response_flags) {
for (const auto& redirect : redirects) for (const auto& redirect : redirects)
client->OnReceiveRedirect(redirect.first, redirect.second); client->OnReceiveRedirect(redirect.first, redirect.second);
if (response_flags & kResponseOnlyRedirectsNoDestination)
return;
if (status.error_code == net::OK) { if (status.error_code == net::OK) {
client->OnReceiveResponse(head); client->OnReceiveResponse(head);
mojo::DataPipe data_pipe(content.size()); mojo::DataPipe data_pipe(content.size());
......
...@@ -32,15 +32,22 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory { ...@@ -32,15 +32,22 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
ResourceRequest request; ResourceRequest request;
}; };
// Bitfield that is used with |SimulateResponseForPendingRequest()|. // Bitfield that is used with |SimulateResponseForPendingRequest()| to
enum SimulateResponseFlags : uint32_t { // control which request is selected.
kDefault = 0x0, enum ResponseMatchFlags : uint32_t {
kMatchDefault = 0x0,
kUrlMatchPrefix = 0x1, // Whether URLs are a match if they start with the kUrlMatchPrefix = 0x1, // Whether URLs are a match if they start with the
// URL passed in to // URL passed in to
// SimulateResponseForPendingRequest // SimulateResponseForPendingRequest
kMostRecentMatch = 0x2, // Start with the most recent requests. kMostRecentMatch = 0x2, // Start with the most recent requests.
}; };
// Flags used with |AddResponse| to control how it produces a response.
enum ResponseProduceFlags : uint32_t {
kResponseDefault = 0,
kResponseOnlyRedirectsNoDestination = 0x1,
};
TestURLLoaderFactory(); TestURLLoaderFactory();
~TestURLLoaderFactory() override; ~TestURLLoaderFactory() override;
...@@ -56,7 +63,8 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory { ...@@ -56,7 +63,8 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
const ResourceResponseHead& head, const ResourceResponseHead& head,
const std::string& content, const std::string& content,
const URLLoaderCompletionStatus& status, const URLLoaderCompletionStatus& status,
const Redirects& redirects = Redirects()); const Redirects& redirects = Redirects(),
ResponseProduceFlags rp_flags = kResponseDefault);
// Simpler version of above for the common case of success or error page. // Simpler version of above for the common case of success or error page.
void AddResponse(const std::string& url, void AddResponse(const std::string& url,
...@@ -96,7 +104,7 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory { ...@@ -96,7 +104,7 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
const network::URLLoaderCompletionStatus& completion_status, const network::URLLoaderCompletionStatus& completion_status,
const ResourceResponseHead& response_head, const ResourceResponseHead& response_head,
const std::string& content, const std::string& content,
SimulateResponseFlags flags = kDefault); ResponseMatchFlags flags = kMatchDefault);
// Sends a response for the given request |request|. // Sends a response for the given request |request|.
// //
...@@ -133,7 +141,8 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory { ...@@ -133,7 +141,8 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
Redirects redirects, Redirects redirects,
ResourceResponseHead head, ResourceResponseHead head,
std::string content, std::string content,
URLLoaderCompletionStatus status); URLLoaderCompletionStatus status,
ResponseProduceFlags response_flags);
struct Response { struct Response {
Response(); Response();
...@@ -144,6 +153,7 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory { ...@@ -144,6 +153,7 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
ResourceResponseHead head; ResourceResponseHead head;
std::string content; std::string content;
URLLoaderCompletionStatus status; URLLoaderCompletionStatus status;
ResponseProduceFlags flags;
}; };
std::map<GURL, Response> responses_; std::map<GURL, Response> responses_;
......
...@@ -289,7 +289,7 @@ TEST_F(TestURLLoaderFactoryTest, SimulateResponseUrlMatch) { ...@@ -289,7 +289,7 @@ TEST_F(TestURLLoaderFactoryTest, SimulateResponseUrlMatch) {
GURL(base_url), ok_status, response_head, /*content=*/"")); GURL(base_url), ok_status, response_head, /*content=*/""));
EXPECT_FALSE(factory()->SimulateResponseForPendingRequest( EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
GURL(base_url), ok_status, response_head, /*content=*/"", GURL(base_url), ok_status, response_head, /*content=*/"",
TestURLLoaderFactory::kDefault)); TestURLLoaderFactory::kMatchDefault));
EXPECT_TRUE(factory()->SimulateResponseForPendingRequest( EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
GURL(base_url), ok_status, response_head, /*content=*/"", GURL(base_url), ok_status, response_head, /*content=*/"",
......
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