685 lines
24 KiB
C++
685 lines
24 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/url_request/url_request_test_util.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/check_op.h"
|
|
#include "base/compiler_specific.h"
|
|
#include "base/location.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/supports_user_data.h"
|
|
#include "base/task/single_thread_task_runner.h"
|
|
#include "base/threading/thread.h"
|
|
#include "net/base/host_port_pair.h"
|
|
#include "net/cert/cert_verifier.h"
|
|
#include "net/cert/ct_policy_enforcer.h"
|
|
#include "net/cert/do_nothing_ct_verifier.h"
|
|
#include "net/cookies/cookie_setting_override.h"
|
|
#include "net/dns/mock_host_resolver.h"
|
|
#include "net/http/http_network_session.h"
|
|
#include "net/http/http_response_headers.h"
|
|
#include "net/http/http_server_properties.h"
|
|
#include "net/http/transport_security_state.h"
|
|
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
|
|
#include "net/proxy_resolution/proxy_retry_info.h"
|
|
#include "net/quic/quic_context.h"
|
|
#include "net/url_request/static_http_user_agent_settings.h"
|
|
#include "net/url_request/url_request_context_builder.h"
|
|
#include "net/url_request/url_request_filter.h"
|
|
#include "net/url_request/url_request_job.h"
|
|
#include "net/url_request/url_request_job_factory.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
|
|
// These constants put the NetworkDelegate events of TestNetworkDelegate
|
|
// into an order. They are used in conjunction with
|
|
// |TestNetworkDelegate::next_states_| to check that we do not send
|
|
// events in the wrong order.
|
|
const int kStageBeforeURLRequest = 1 << 0;
|
|
const int kStageBeforeStartTransaction = 1 << 1;
|
|
const int kStageHeadersReceived = 1 << 2;
|
|
const int kStageBeforeRedirect = 1 << 3;
|
|
const int kStageResponseStarted = 1 << 4;
|
|
const int kStageCompletedSuccess = 1 << 5;
|
|
const int kStageCompletedError = 1 << 6;
|
|
const int kStageURLRequestDestroyed = 1 << 7;
|
|
const int kStageDestruction = 1 << 8;
|
|
|
|
const char kTestNetworkDelegateRequestIdKey[] =
|
|
"TestNetworkDelegateRequestIdKey";
|
|
|
|
class TestRequestId : public base::SupportsUserData::Data {
|
|
public:
|
|
explicit TestRequestId(int id) : id_(id) {}
|
|
~TestRequestId() override = default;
|
|
|
|
int id() const { return id_; }
|
|
|
|
private:
|
|
const int id_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
std::unique_ptr<URLRequestContextBuilder> CreateTestURLRequestContextBuilder() {
|
|
auto builder = std::make_unique<URLRequestContextBuilder>();
|
|
builder->set_host_resolver(std::make_unique<MockCachingHostResolver>(
|
|
/*cache_invalidation_num=*/0,
|
|
/*default_result=*/MockHostResolverBase::RuleResolver::
|
|
GetLocalhostResult()));
|
|
builder->set_proxy_resolution_service(
|
|
ConfiguredProxyResolutionService::CreateDirect());
|
|
builder->SetCertVerifier(
|
|
CertVerifier::CreateDefault(/*cert_net_fetcher=*/nullptr));
|
|
builder->set_ct_policy_enforcer(std::make_unique<DefaultCTPolicyEnforcer>());
|
|
builder->set_ssl_config_service(std::make_unique<SSLConfigServiceDefaults>());
|
|
builder->SetHttpAuthHandlerFactory(HttpAuthHandlerFactory::CreateDefault());
|
|
builder->SetHttpServerProperties(std::make_unique<HttpServerProperties>());
|
|
builder->set_quic_context(std::make_unique<QuicContext>());
|
|
builder->SetCookieStore(std::make_unique<CookieMonster>(/*store=*/nullptr,
|
|
/*netlog=*/nullptr));
|
|
builder->set_http_user_agent_settings(
|
|
std::make_unique<StaticHttpUserAgentSettings>("en-us,fr", std::string()));
|
|
return builder;
|
|
}
|
|
|
|
TestURLRequestContextGetter::TestURLRequestContextGetter(
|
|
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner)
|
|
: network_task_runner_(network_task_runner) {
|
|
DCHECK(network_task_runner_.get());
|
|
}
|
|
|
|
TestURLRequestContextGetter::TestURLRequestContextGetter(
|
|
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
|
|
std::unique_ptr<URLRequestContext> context)
|
|
: network_task_runner_(network_task_runner), context_(std::move(context)) {
|
|
DCHECK(network_task_runner_.get());
|
|
}
|
|
|
|
TestURLRequestContextGetter::~TestURLRequestContextGetter() = default;
|
|
|
|
URLRequestContext* TestURLRequestContextGetter::GetURLRequestContext() {
|
|
if (is_shut_down_)
|
|
return nullptr;
|
|
|
|
if (!context_.get())
|
|
context_ = CreateTestURLRequestContextBuilder()->Build();
|
|
return context_.get();
|
|
}
|
|
|
|
void TestURLRequestContextGetter::NotifyContextShuttingDown() {
|
|
// This should happen before call to base NotifyContextShuttingDown() per that
|
|
// method's doc comments.
|
|
is_shut_down_ = true;
|
|
|
|
URLRequestContextGetter::NotifyContextShuttingDown();
|
|
context_ = nullptr;
|
|
}
|
|
|
|
scoped_refptr<base::SingleThreadTaskRunner>
|
|
TestURLRequestContextGetter::GetNetworkTaskRunner() const {
|
|
return network_task_runner_;
|
|
}
|
|
|
|
const int TestDelegate::kBufferSize;
|
|
|
|
TestDelegate::TestDelegate()
|
|
: buf_(base::MakeRefCounted<IOBuffer>(kBufferSize)) {}
|
|
|
|
TestDelegate::~TestDelegate() = default;
|
|
|
|
void TestDelegate::RunUntilComplete() {
|
|
use_legacy_on_complete_ = false;
|
|
base::RunLoop run_loop;
|
|
on_complete_ = run_loop.QuitClosure();
|
|
run_loop.Run();
|
|
}
|
|
|
|
void TestDelegate::RunUntilRedirect() {
|
|
use_legacy_on_complete_ = false;
|
|
base::RunLoop run_loop;
|
|
on_redirect_ = run_loop.QuitClosure();
|
|
run_loop.Run();
|
|
}
|
|
|
|
void TestDelegate::RunUntilAuthRequired() {
|
|
use_legacy_on_complete_ = false;
|
|
base::RunLoop run_loop;
|
|
on_auth_required_ = run_loop.QuitClosure();
|
|
run_loop.Run();
|
|
}
|
|
|
|
int TestDelegate::OnConnected(URLRequest* request,
|
|
const TransportInfo& info,
|
|
CompletionOnceCallback callback) {
|
|
transports_.push_back(info);
|
|
|
|
if (on_connected_run_callback_) {
|
|
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE, base::BindOnce(std::move(callback), on_connected_result_));
|
|
return net::ERR_IO_PENDING;
|
|
}
|
|
|
|
return on_connected_result_;
|
|
}
|
|
|
|
void TestDelegate::OnReceivedRedirect(URLRequest* request,
|
|
const RedirectInfo& redirect_info,
|
|
bool* defer_redirect) {
|
|
EXPECT_TRUE(request->is_redirecting());
|
|
|
|
redirect_info_ = redirect_info;
|
|
|
|
received_redirect_count_++;
|
|
if (on_redirect_) {
|
|
*defer_redirect = true;
|
|
std::move(on_redirect_).Run();
|
|
} else if (cancel_in_rr_) {
|
|
request->Cancel();
|
|
}
|
|
}
|
|
|
|
void TestDelegate::OnAuthRequired(URLRequest* request,
|
|
const AuthChallengeInfo& auth_info) {
|
|
auth_required_ = true;
|
|
if (on_auth_required_) {
|
|
std::move(on_auth_required_).Run();
|
|
return;
|
|
}
|
|
if (!credentials_.Empty()) {
|
|
request->SetAuth(credentials_);
|
|
} else {
|
|
request->CancelAuth();
|
|
}
|
|
}
|
|
|
|
void TestDelegate::OnSSLCertificateError(URLRequest* request,
|
|
int net_error,
|
|
const SSLInfo& ssl_info,
|
|
bool fatal) {
|
|
// The caller can control whether it needs all SSL requests to go through,
|
|
// independent of any possible errors, or whether it wants SSL errors to
|
|
// cancel the request.
|
|
have_certificate_errors_ = true;
|
|
certificate_errors_are_fatal_ = fatal;
|
|
certificate_net_error_ = net_error;
|
|
if (allow_certificate_errors_)
|
|
request->ContinueDespiteLastError();
|
|
else
|
|
request->Cancel();
|
|
}
|
|
|
|
void TestDelegate::OnResponseStarted(URLRequest* request, int net_error) {
|
|
// It doesn't make sense for the request to have IO pending at this point.
|
|
DCHECK_NE(ERR_IO_PENDING, net_error);
|
|
EXPECT_FALSE(request->is_redirecting());
|
|
|
|
response_started_count_++;
|
|
request_status_ = net_error;
|
|
if (cancel_in_rs_) {
|
|
request_status_ = request->Cancel();
|
|
// Canceling |request| will cause OnResponseCompleted() to be called.
|
|
} else if (net_error != OK) {
|
|
request_failed_ = true;
|
|
OnResponseCompleted(request);
|
|
} else {
|
|
// Initiate the first read.
|
|
int bytes_read = request->Read(buf_.get(), kBufferSize);
|
|
if (bytes_read >= 0)
|
|
OnReadCompleted(request, bytes_read);
|
|
else if (bytes_read != ERR_IO_PENDING)
|
|
OnResponseCompleted(request);
|
|
}
|
|
}
|
|
|
|
void TestDelegate::OnReadCompleted(URLRequest* request, int bytes_read) {
|
|
// It doesn't make sense for the request to have IO pending at this point.
|
|
DCHECK_NE(bytes_read, ERR_IO_PENDING);
|
|
|
|
// If you've reached this, you've either called "RunUntilComplete" or are
|
|
// using legacy "QuitCurrent*Deprecated". If this DCHECK fails, that probably
|
|
// means you've run "RunUntilRedirect" or "RunUntilAuthRequired" and haven't
|
|
// redirected/auth-challenged
|
|
DCHECK(on_complete_ || use_legacy_on_complete_);
|
|
|
|
// If the request was cancelled in a redirect, it should not signal
|
|
// OnReadCompleted. Note that |cancel_in_rs_| may be true due to
|
|
// https://crbug.com/564848.
|
|
EXPECT_FALSE(cancel_in_rr_);
|
|
|
|
if (response_started_count_ == 0)
|
|
received_data_before_response_ = true;
|
|
|
|
if (bytes_read >= 0) {
|
|
// There is data to read.
|
|
received_bytes_count_ += bytes_read;
|
|
|
|
// Consume the data.
|
|
data_received_.append(buf_->data(), bytes_read);
|
|
|
|
if (cancel_in_rd_) {
|
|
request_status_ = request->Cancel();
|
|
// If bytes_read is 0, won't get a notification on cancelation.
|
|
if (bytes_read == 0) {
|
|
if (use_legacy_on_complete_)
|
|
base::RunLoop::QuitCurrentWhenIdleDeprecated();
|
|
else
|
|
std::move(on_complete_).Run();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// If it was not end of stream, request to read more.
|
|
while (bytes_read > 0) {
|
|
bytes_read = request->Read(buf_.get(), kBufferSize);
|
|
if (bytes_read > 0) {
|
|
data_received_.append(buf_->data(), bytes_read);
|
|
received_bytes_count_ += bytes_read;
|
|
}
|
|
}
|
|
|
|
request_status_ = bytes_read;
|
|
if (request_status_ != ERR_IO_PENDING)
|
|
OnResponseCompleted(request);
|
|
else if (cancel_in_rd_pending_)
|
|
request_status_ = request->Cancel();
|
|
}
|
|
|
|
void TestDelegate::OnResponseCompleted(URLRequest* request) {
|
|
response_completed_ = true;
|
|
if (use_legacy_on_complete_)
|
|
base::RunLoop::QuitCurrentWhenIdleDeprecated();
|
|
else
|
|
std::move(on_complete_).Run();
|
|
}
|
|
|
|
TestNetworkDelegate::TestNetworkDelegate() = default;
|
|
|
|
TestNetworkDelegate::~TestNetworkDelegate() {
|
|
for (auto i = next_states_.begin(); i != next_states_.end(); ++i) {
|
|
event_order_[i->first] += "~TestNetworkDelegate\n";
|
|
EXPECT_TRUE(i->second & kStageDestruction) << event_order_[i->first];
|
|
}
|
|
}
|
|
|
|
bool TestNetworkDelegate::GetLoadTimingInfoBeforeRedirect(
|
|
LoadTimingInfo* load_timing_info_before_redirect) const {
|
|
*load_timing_info_before_redirect = load_timing_info_before_redirect_;
|
|
return has_load_timing_info_before_redirect_;
|
|
}
|
|
|
|
void TestNetworkDelegate::InitRequestStatesIfNew(int request_id) {
|
|
if (next_states_.find(request_id) == next_states_.end()) {
|
|
// TODO(davidben): Although the URLRequest documentation does not allow
|
|
// calling Cancel() before Start(), the ResourceLoader does so. URLRequest's
|
|
// destructor also calls Cancel. Either officially support this or fix the
|
|
// ResourceLoader code.
|
|
next_states_[request_id] = kStageBeforeURLRequest | kStageCompletedError;
|
|
event_order_[request_id] = "";
|
|
}
|
|
}
|
|
|
|
int TestNetworkDelegate::OnBeforeURLRequest(URLRequest* request,
|
|
CompletionOnceCallback callback,
|
|
GURL* new_url) {
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnBeforeURLRequest\n";
|
|
EXPECT_TRUE(next_states_[req_id] & kStageBeforeURLRequest) <<
|
|
event_order_[req_id];
|
|
next_states_[req_id] =
|
|
kStageBeforeStartTransaction |
|
|
kStageResponseStarted | // data: URLs do not trigger sending headers
|
|
kStageBeforeRedirect | // a delegate can trigger a redirection
|
|
kStageCompletedError; // request canceled by delegate
|
|
created_requests_++;
|
|
return OK;
|
|
}
|
|
|
|
int TestNetworkDelegate::OnBeforeStartTransaction(
|
|
URLRequest* request,
|
|
const HttpRequestHeaders& headers,
|
|
OnBeforeStartTransactionCallback callback) {
|
|
if (before_start_transaction_fails_)
|
|
return ERR_FAILED;
|
|
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnBeforeStartTransaction\n";
|
|
EXPECT_TRUE(next_states_[req_id] & kStageBeforeStartTransaction)
|
|
<< event_order_[req_id];
|
|
next_states_[req_id] =
|
|
kStageHeadersReceived | kStageCompletedError | kStageBeforeRedirect;
|
|
before_start_transaction_count_++;
|
|
return OK;
|
|
}
|
|
|
|
int TestNetworkDelegate::OnHeadersReceived(
|
|
URLRequest* request,
|
|
CompletionOnceCallback callback,
|
|
const HttpResponseHeaders* original_response_headers,
|
|
scoped_refptr<HttpResponseHeaders>* override_response_headers,
|
|
const IPEndPoint& endpoint,
|
|
absl::optional<GURL>* preserve_fragment_on_redirect_url) {
|
|
EXPECT_FALSE(preserve_fragment_on_redirect_url->has_value());
|
|
int req_id = GetRequestId(request);
|
|
bool is_first_response =
|
|
event_order_[req_id].find("OnHeadersReceived\n") == std::string::npos;
|
|
event_order_[req_id] += "OnHeadersReceived\n";
|
|
InitRequestStatesIfNew(req_id);
|
|
EXPECT_TRUE(next_states_[req_id] & kStageHeadersReceived) <<
|
|
event_order_[req_id];
|
|
next_states_[req_id] =
|
|
kStageBeforeRedirect |
|
|
kStageResponseStarted |
|
|
kStageCompletedError; // e.g. proxy resolution problem
|
|
|
|
// Basic authentication sends a second request from the URLRequestHttpJob
|
|
// layer before the URLRequest reports that a response has started.
|
|
next_states_[req_id] |= kStageBeforeStartTransaction;
|
|
|
|
if (!redirect_on_headers_received_url_.is_empty()) {
|
|
*override_response_headers = base::MakeRefCounted<HttpResponseHeaders>(
|
|
original_response_headers->raw_headers());
|
|
(*override_response_headers)->ReplaceStatusLine("HTTP/1.1 302 Found");
|
|
(*override_response_headers)->RemoveHeader("Location");
|
|
(*override_response_headers)
|
|
->AddHeader("Location", redirect_on_headers_received_url_.spec());
|
|
|
|
redirect_on_headers_received_url_ = GURL();
|
|
|
|
// Since both values are absl::optionals, can just copy this over.
|
|
*preserve_fragment_on_redirect_url = preserve_fragment_on_redirect_url_;
|
|
} else if (add_header_to_first_response_ && is_first_response) {
|
|
*override_response_headers = base::MakeRefCounted<HttpResponseHeaders>(
|
|
original_response_headers->raw_headers());
|
|
(*override_response_headers)
|
|
->AddHeader("X-Network-Delegate", "Greetings, planet");
|
|
}
|
|
|
|
headers_received_count_++;
|
|
return OK;
|
|
}
|
|
|
|
void TestNetworkDelegate::OnBeforeRedirect(URLRequest* request,
|
|
const GURL& new_location) {
|
|
load_timing_info_before_redirect_ = LoadTimingInfo();
|
|
request->GetLoadTimingInfo(&load_timing_info_before_redirect_);
|
|
has_load_timing_info_before_redirect_ = true;
|
|
EXPECT_FALSE(load_timing_info_before_redirect_.request_start_time.is_null());
|
|
EXPECT_FALSE(load_timing_info_before_redirect_.request_start.is_null());
|
|
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnBeforeRedirect\n";
|
|
EXPECT_TRUE(next_states_[req_id] & kStageBeforeRedirect) <<
|
|
event_order_[req_id];
|
|
next_states_[req_id] =
|
|
kStageBeforeURLRequest | // HTTP redirects trigger this.
|
|
kStageBeforeStartTransaction | // Redirects from the network delegate do
|
|
// not
|
|
// trigger onBeforeURLRequest.
|
|
kStageCompletedError;
|
|
|
|
// A redirect can lead to a file or a data URL. In this case, we do not send
|
|
// headers.
|
|
next_states_[req_id] |= kStageResponseStarted;
|
|
}
|
|
|
|
void TestNetworkDelegate::OnResponseStarted(URLRequest* request,
|
|
int net_error) {
|
|
DCHECK_NE(ERR_IO_PENDING, net_error);
|
|
|
|
LoadTimingInfo load_timing_info;
|
|
request->GetLoadTimingInfo(&load_timing_info);
|
|
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
|
|
EXPECT_FALSE(load_timing_info.request_start.is_null());
|
|
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnResponseStarted\n";
|
|
EXPECT_TRUE(next_states_[req_id] & kStageResponseStarted)
|
|
<< event_order_[req_id];
|
|
next_states_[req_id] = kStageCompletedSuccess | kStageCompletedError;
|
|
if (net_error == ERR_ABORTED)
|
|
return;
|
|
|
|
if (net_error != OK) {
|
|
error_count_++;
|
|
last_error_ = net_error;
|
|
}
|
|
}
|
|
|
|
void TestNetworkDelegate::OnCompleted(URLRequest* request,
|
|
bool started,
|
|
int net_error) {
|
|
DCHECK_NE(net_error, net::ERR_IO_PENDING);
|
|
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnCompleted\n";
|
|
// Expect "Success -> (next_states_ & kStageCompletedSuccess)"
|
|
// is logically identical to
|
|
// Expect "!(Success) || (next_states_ & kStageCompletedSuccess)"
|
|
EXPECT_TRUE(net_error != OK ||
|
|
(next_states_[req_id] & kStageCompletedSuccess))
|
|
<< event_order_[req_id];
|
|
EXPECT_TRUE(net_error == OK || (next_states_[req_id] & kStageCompletedError))
|
|
<< event_order_[req_id];
|
|
next_states_[req_id] = kStageURLRequestDestroyed;
|
|
completed_requests_++;
|
|
if (net_error == ERR_ABORTED) {
|
|
canceled_requests_++;
|
|
} else if (net_error != OK) {
|
|
error_count_++;
|
|
last_error_ = net_error;
|
|
} else {
|
|
DCHECK_EQ(OK, net_error);
|
|
}
|
|
}
|
|
|
|
void TestNetworkDelegate::OnURLRequestDestroyed(URLRequest* request) {
|
|
int req_id = GetRequestId(request);
|
|
InitRequestStatesIfNew(req_id);
|
|
event_order_[req_id] += "OnURLRequestDestroyed\n";
|
|
EXPECT_TRUE(next_states_[req_id] & kStageURLRequestDestroyed) <<
|
|
event_order_[req_id];
|
|
next_states_[req_id] = kStageDestruction;
|
|
destroyed_requests_++;
|
|
}
|
|
|
|
bool TestNetworkDelegate::OnAnnotateAndMoveUserBlockedCookies(
|
|
const URLRequest& request,
|
|
const net::FirstPartySetMetadata& first_party_set_metadata,
|
|
net::CookieAccessResultList& maybe_included_cookies,
|
|
net::CookieAccessResultList& excluded_cookies) {
|
|
RecordCookieSettingOverrides(request.cookie_setting_overrides());
|
|
bool allow = true;
|
|
if (cookie_options_bit_mask_ & NO_GET_COOKIES)
|
|
allow = false;
|
|
|
|
if (!allow) {
|
|
blocked_annotate_cookies_count_++;
|
|
ExcludeAllCookies(CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
|
|
maybe_included_cookies, excluded_cookies);
|
|
}
|
|
|
|
return allow;
|
|
}
|
|
|
|
NetworkDelegate::PrivacySetting TestNetworkDelegate::OnForcePrivacyMode(
|
|
const URLRequest& request) const {
|
|
RecordCookieSettingOverrides(request.cookie_setting_overrides());
|
|
return NetworkDelegate::PrivacySetting::kStateAllowed;
|
|
}
|
|
|
|
bool TestNetworkDelegate::OnCanSetCookie(const URLRequest& request,
|
|
const net::CanonicalCookie& cookie,
|
|
CookieOptions* options) {
|
|
RecordCookieSettingOverrides(request.cookie_setting_overrides());
|
|
bool allow = true;
|
|
if (cookie_options_bit_mask_ & NO_SET_COOKIE)
|
|
allow = false;
|
|
|
|
if (!allow) {
|
|
blocked_set_cookie_count_++;
|
|
} else {
|
|
set_cookie_count_++;
|
|
}
|
|
|
|
return allow;
|
|
}
|
|
|
|
bool TestNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
|
|
const URLRequest& request,
|
|
const GURL& target_url,
|
|
const GURL& referrer_url) const {
|
|
return cancel_request_with_policy_violating_referrer_;
|
|
}
|
|
|
|
absl::optional<FirstPartySetsCacheFilter::MatchInfo>
|
|
TestNetworkDelegate::OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
|
|
const SchemefulSite& request_site,
|
|
base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
|
|
const {
|
|
return fps_cache_filter_.GetMatchInfo(request_site);
|
|
}
|
|
|
|
int TestNetworkDelegate::GetRequestId(URLRequest* request) {
|
|
TestRequestId* test_request_id = reinterpret_cast<TestRequestId*>(
|
|
request->GetUserData(kTestNetworkDelegateRequestIdKey));
|
|
if (test_request_id)
|
|
return test_request_id->id();
|
|
int id = next_request_id_++;
|
|
request->SetUserData(kTestNetworkDelegateRequestIdKey,
|
|
std::make_unique<TestRequestId>(id));
|
|
return id;
|
|
}
|
|
|
|
FilteringTestNetworkDelegate::FilteringTestNetworkDelegate() = default;
|
|
FilteringTestNetworkDelegate::~FilteringTestNetworkDelegate() = default;
|
|
|
|
bool FilteringTestNetworkDelegate::OnCanSetCookie(
|
|
const URLRequest& request,
|
|
const net::CanonicalCookie& cookie,
|
|
CookieOptions* options) {
|
|
// Filter out cookies with the same name as |cookie_name_filter_| and
|
|
// combine with |allowed_from_caller|.
|
|
bool allowed = cookie.Name() != cookie_name_filter_;
|
|
|
|
++set_cookie_called_count_;
|
|
|
|
if (!allowed)
|
|
++blocked_set_cookie_count_;
|
|
|
|
// Call the nested delegate's method first to avoid a short circuit.
|
|
return TestNetworkDelegate::OnCanSetCookie(request, cookie, options) &&
|
|
allowed;
|
|
}
|
|
|
|
NetworkDelegate::PrivacySetting
|
|
FilteringTestNetworkDelegate::OnForcePrivacyMode(
|
|
const URLRequest& request) const {
|
|
if (force_privacy_mode_) {
|
|
return partitioned_state_allowed_
|
|
? NetworkDelegate::PrivacySetting::kPartitionedStateAllowedOnly
|
|
: NetworkDelegate::PrivacySetting::kStateDisallowed;
|
|
}
|
|
|
|
return TestNetworkDelegate::OnForcePrivacyMode(request);
|
|
}
|
|
|
|
bool FilteringTestNetworkDelegate::OnAnnotateAndMoveUserBlockedCookies(
|
|
const URLRequest& request,
|
|
const net::FirstPartySetMetadata& first_party_set_metadata,
|
|
net::CookieAccessResultList& maybe_included_cookies,
|
|
net::CookieAccessResultList& excluded_cookies) {
|
|
// Filter out cookies if |block_annotate_cookies_| is set and
|
|
// combine with |allowed_from_caller|.
|
|
bool allowed = !block_annotate_cookies_;
|
|
|
|
++annotate_cookies_called_count_;
|
|
|
|
if (!allowed) {
|
|
++blocked_annotate_cookies_count_;
|
|
ExcludeAllCookies(net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
|
|
maybe_included_cookies, excluded_cookies);
|
|
}
|
|
|
|
if (allowed && block_get_cookies_by_name_ && !cookie_name_filter_.empty()) {
|
|
for (auto& cookie : maybe_included_cookies) {
|
|
if (cookie.cookie.Name().find(cookie_name_filter_) != std::string::npos) {
|
|
cookie.access_result.status.AddExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
|
|
}
|
|
}
|
|
for (auto& cookie : excluded_cookies) {
|
|
if (cookie.cookie.Name().find(cookie_name_filter_) != std::string::npos) {
|
|
cookie.access_result.status.AddExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
|
|
}
|
|
}
|
|
|
|
MoveExcludedCookies(maybe_included_cookies, excluded_cookies);
|
|
}
|
|
|
|
// Call the nested delegate's method first to avoid a short circuit.
|
|
return TestNetworkDelegate::OnAnnotateAndMoveUserBlockedCookies(
|
|
request, first_party_set_metadata, maybe_included_cookies,
|
|
excluded_cookies) &&
|
|
allowed;
|
|
}
|
|
|
|
// URLRequestInterceptor that intercepts only the first request it sees,
|
|
// returning the provided URLRequestJob.
|
|
class TestScopedURLInterceptor::TestRequestInterceptor
|
|
: public URLRequestInterceptor {
|
|
public:
|
|
explicit TestRequestInterceptor(std::unique_ptr<URLRequestJob> intercept_job)
|
|
: intercept_job_(std::move(intercept_job)) {}
|
|
|
|
~TestRequestInterceptor() override { CHECK(safe_to_delete_); }
|
|
|
|
std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
|
|
URLRequest* request) const override {
|
|
return std::move(intercept_job_);
|
|
}
|
|
|
|
bool job_used() const { return intercept_job_.get() == nullptr; }
|
|
void set_safe_to_delete() { safe_to_delete_ = true; }
|
|
|
|
private:
|
|
mutable std::unique_ptr<URLRequestJob> intercept_job_;
|
|
// This is used to catch chases where the TestRequestInterceptor is destroyed
|
|
// before the TestScopedURLInterceptor.
|
|
bool safe_to_delete_ = false;
|
|
};
|
|
|
|
TestScopedURLInterceptor::TestScopedURLInterceptor(
|
|
const GURL& url,
|
|
std::unique_ptr<URLRequestJob> intercept_job)
|
|
: url_(url) {
|
|
std::unique_ptr<TestRequestInterceptor> interceptor =
|
|
std::make_unique<TestRequestInterceptor>(std::move(intercept_job));
|
|
interceptor_ = interceptor.get();
|
|
URLRequestFilter::GetInstance()->AddUrlInterceptor(url_,
|
|
std::move(interceptor));
|
|
}
|
|
|
|
TestScopedURLInterceptor::~TestScopedURLInterceptor() {
|
|
DCHECK(interceptor_->job_used());
|
|
interceptor_->set_safe_to_delete();
|
|
interceptor_ = nullptr;
|
|
URLRequestFilter::GetInstance()->RemoveUrlHandler(url_);
|
|
}
|
|
|
|
} // namespace net
|