123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/network/network_service_network_delegate.h"
- #include <string>
- #include "base/bind.h"
- #include "base/debug/dump_without_crashing.h"
- #include "base/stl_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "build/build_config.h"
- #include "components/domain_reliability/monitor.h"
- #include "net/base/features.h"
- #include "net/base/isolation_info.h"
- #include "net/base/load_flags.h"
- #include "net/base/net_errors.h"
- #include "net/cookies/same_party_context.h"
- #include "net/url_request/referrer_policy.h"
- #include "net/url_request/url_request.h"
- #include "services/network/cookie_manager.h"
- #include "services/network/network_context.h"
- #include "services/network/network_service.h"
- #include "services/network/network_service_proxy_delegate.h"
- #include "services/network/pending_callback_chain.h"
- #include "services/network/url_loader.h"
- #include "url/gurl.h"
- #if !BUILDFLAG(IS_IOS)
- #include "services/network/websocket.h"
- #endif
- namespace network {
- namespace {
- const char kClearSiteDataHeader[] = "Clear-Site-Data";
- } // anonymous namespace
- NetworkServiceNetworkDelegate::NetworkServiceNetworkDelegate(
- bool enable_referrers,
- bool validate_referrer_policy_on_initial_request,
- mojo::PendingRemote<mojom::ProxyErrorClient> proxy_error_client_remote,
- NetworkContext* network_context)
- : enable_referrers_(enable_referrers),
- validate_referrer_policy_on_initial_request_(
- validate_referrer_policy_on_initial_request),
- network_context_(network_context) {
- if (proxy_error_client_remote)
- proxy_error_client_.Bind(std::move(proxy_error_client_remote));
- }
- NetworkServiceNetworkDelegate::~NetworkServiceNetworkDelegate() = default;
- void NetworkServiceNetworkDelegate::MaybeTruncateReferrer(
- net::URLRequest* const request,
- const GURL& effective_url) {
- if (!enable_referrers_) {
- request->SetReferrer(std::string());
- request->set_referrer_policy(net::ReferrerPolicy::NO_REFERRER);
- return;
- }
- if (base::FeatureList::IsEnabled(
- net::features::kCapReferrerToOriginOnCrossOrigin)) {
- if (!url::IsSameOriginWith(effective_url, GURL(request->referrer()))) {
- auto capped_referrer = url::Origin::Create(GURL(request->referrer()));
- request->SetReferrer(capped_referrer.GetURL().spec());
- }
- }
- }
- int NetworkServiceNetworkDelegate::OnBeforeURLRequest(
- net::URLRequest* request,
- net::CompletionOnceCallback callback,
- GURL* new_url) {
- DCHECK(request);
- auto* const loader = URLLoader::ForRequest(*request);
- const GURL* effective_url = nullptr;
- if (loader && loader->new_redirect_url()) {
- DCHECK(new_url);
- *new_url = loader->new_redirect_url().value();
- effective_url = new_url;
- } else {
- effective_url = &request->url();
- }
- MaybeTruncateReferrer(request, *effective_url);
- if (!loader)
- return net::OK;
- NetworkService* network_service = network_context_->network_service();
- if (network_service) {
- loader->SetEnableReportingRawHeaders(network_service->HasRawHeadersAccess(
- loader->GetProcessId(), *effective_url));
- }
- return net::OK;
- }
- int NetworkServiceNetworkDelegate::OnBeforeStartTransaction(
- net::URLRequest* request,
- const net::HttpRequestHeaders& headers,
- OnBeforeStartTransactionCallback callback) {
- URLLoader* url_loader = URLLoader::ForRequest(*request);
- if (url_loader)
- return url_loader->OnBeforeStartTransaction(headers, std::move(callback));
- #if !BUILDFLAG(IS_IOS)
- WebSocket* web_socket = WebSocket::ForRequest(*request);
- if (web_socket)
- return web_socket->OnBeforeStartTransaction(headers, std::move(callback));
- #endif // !BUILDFLAG(IS_IOS)
- return net::OK;
- }
- int NetworkServiceNetworkDelegate::OnHeadersReceived(
- net::URLRequest* request,
- net::CompletionOnceCallback callback,
- const net::HttpResponseHeaders* original_response_headers,
- scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
- const net::IPEndPoint& endpoint,
- absl::optional<GURL>* preserve_fragment_on_redirect_url) {
- auto chain = base::MakeRefCounted<PendingCallbackChain>(std::move(callback));
- URLLoader* url_loader = URLLoader::ForRequest(*request);
- if (url_loader) {
- chain->AddResult(url_loader->OnHeadersReceived(
- chain->CreateCallback(), original_response_headers,
- override_response_headers, endpoint,
- preserve_fragment_on_redirect_url));
- }
- #if !BUILDFLAG(IS_IOS)
- WebSocket* web_socket = WebSocket::ForRequest(*request);
- if (web_socket) {
- chain->AddResult(web_socket->OnHeadersReceived(
- chain->CreateCallback(), original_response_headers,
- override_response_headers, preserve_fragment_on_redirect_url));
- }
- #endif // !BUILDFLAG(IS_IOS)
- chain->AddResult(HandleClearSiteDataHeader(request, chain->CreateCallback(),
- original_response_headers));
- return chain->GetResult();
- }
- void NetworkServiceNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
- const GURL& new_location) {
- if (network_context_->domain_reliability_monitor())
- network_context_->domain_reliability_monitor()->OnBeforeRedirect(request);
- }
- void NetworkServiceNetworkDelegate::OnResponseStarted(net::URLRequest* request,
- int net_error) {
- ForwardProxyErrors(net_error);
- }
- void NetworkServiceNetworkDelegate::OnCompleted(net::URLRequest* request,
- bool started,
- int net_error) {
- // TODO(mmenke): Once the network service ships on all platforms, can move
- // this logic into URLLoader's completion method.
- DCHECK_NE(net::ERR_IO_PENDING, net_error);
- if (network_context_->domain_reliability_monitor()) {
- network_context_->domain_reliability_monitor()->OnCompleted(
- request, started, net_error);
- }
- ForwardProxyErrors(net_error);
- }
- void NetworkServiceNetworkDelegate::OnPACScriptError(
- int line_number,
- const std::u16string& error) {
- if (!proxy_error_client_)
- return;
- proxy_error_client_->OnPACScriptError(line_number, base::UTF16ToUTF8(error));
- }
- bool NetworkServiceNetworkDelegate::OnAnnotateAndMoveUserBlockedCookies(
- const net::URLRequest& request,
- net::CookieAccessResultList& maybe_included_cookies,
- net::CookieAccessResultList& excluded_cookies) {
- if (!network_context_->cookie_manager()
- ->cookie_settings()
- .AnnotateAndMoveUserBlockedCookies(
- request.url(), request.site_for_cookies(),
- base::OptionalOrNullptr(
- request.isolation_info().top_frame_origin()),
- maybe_included_cookies, excluded_cookies)) {
- // CookieSettings has already moved and annotated the cookies.
- return false;
- }
- bool allowed = true;
- URLLoader* url_loader = URLLoader::ForRequest(request);
- if (url_loader) {
- allowed =
- url_loader->AllowCookies(request.url(), request.site_for_cookies());
- #if !BUILDFLAG(IS_IOS)
- } else {
- WebSocket* web_socket = WebSocket::ForRequest(request);
- if (web_socket) {
- allowed = web_socket->AllowCookies(request.url());
- }
- #endif // !BUILDFLAG(IS_IOS)
- }
- if (!allowed)
- ExcludeAllCookies(net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
- maybe_included_cookies, excluded_cookies);
- return allowed;
- }
- bool NetworkServiceNetworkDelegate::OnCanSetCookie(
- const net::URLRequest& request,
- const net::CanonicalCookie& cookie,
- net::CookieOptions* options) {
- bool allowed =
- network_context_->cookie_manager()->cookie_settings().IsCookieAccessible(
- cookie, request.url(), request.site_for_cookies(),
- request.isolation_info().top_frame_origin());
- if (!allowed)
- return false;
- URLLoader* url_loader = URLLoader::ForRequest(request);
- if (url_loader)
- return url_loader->AllowCookies(request.url(), request.site_for_cookies());
- #if !BUILDFLAG(IS_IOS)
- WebSocket* web_socket = WebSocket::ForRequest(request);
- if (web_socket)
- return web_socket->AllowCookies(request.url());
- #endif // !BUILDFLAG(IS_IOS)
- return true;
- }
- net::NetworkDelegate::PrivacySetting
- NetworkServiceNetworkDelegate::OnForcePrivacyMode(
- const GURL& url,
- const net::SiteForCookies& site_for_cookies,
- const absl::optional<url::Origin>& top_frame_origin,
- net::SamePartyContext::Type same_party_context_type) const {
- return network_context_->cookie_manager()
- ->cookie_settings()
- .IsPrivacyModeEnabled(url, site_for_cookies, top_frame_origin,
- same_party_context_type);
- }
- bool NetworkServiceNetworkDelegate::
- OnCancelURLRequestWithPolicyViolatingReferrerHeader(
- const net::URLRequest& request,
- const GURL& target_url,
- const GURL& referrer_url) const {
- // TODO(mmenke): Once the network service has shipped on all platforms,
- // consider moving this logic into URLLoader, and removing this method from
- // NetworkDelegate. Can just have a DCHECK in URLRequest instead.
- if (!validate_referrer_policy_on_initial_request_)
- return false;
- LOG(ERROR) << "Cancelling request to " << target_url
- << " with invalid referrer " << referrer_url;
- // Record information to help debug issues like http://crbug.com/422871.
- if (target_url.SchemeIsHTTPOrHTTPS()) {
- auto referrer_policy = request.referrer_policy();
- base::debug::Alias(&referrer_policy);
- DEBUG_ALIAS_FOR_GURL(target_buf, target_url);
- DEBUG_ALIAS_FOR_GURL(referrer_buf, referrer_url);
- base::debug::DumpWithoutCrashing();
- }
- return true;
- }
- bool NetworkServiceNetworkDelegate::OnCanQueueReportingReport(
- const url::Origin& origin) const {
- return network_context_->cookie_manager()
- ->cookie_settings()
- .IsFullCookieAccessAllowed(origin.GetURL(), origin.GetURL(),
- QueryReason::kSiteStorage);
- }
- void NetworkServiceNetworkDelegate::OnCanSendReportingReports(
- std::set<url::Origin> origins,
- base::OnceCallback<void(std::set<url::Origin>)> result_callback) const {
- auto* client = network_context_->client();
- if (!client) {
- origins.clear();
- std::move(result_callback).Run(std::move(origins));
- return;
- }
- if (network_context_->SkipReportingPermissionCheck()) {
- std::move(result_callback).Run(std::move(origins));
- return;
- }
- std::vector<url::Origin> origin_vector;
- std::copy(origins.begin(), origins.end(), std::back_inserter(origin_vector));
- client->OnCanSendReportingReports(
- origin_vector,
- base::BindOnce(
- &NetworkServiceNetworkDelegate::FinishedCanSendReportingReports,
- weak_ptr_factory_.GetWeakPtr(), std::move(result_callback)));
- }
- bool NetworkServiceNetworkDelegate::OnCanSetReportingClient(
- const url::Origin& origin,
- const GURL& endpoint) const {
- return network_context_->cookie_manager()
- ->cookie_settings()
- .IsFullCookieAccessAllowed(origin.GetURL(), origin.GetURL(),
- QueryReason::kSiteStorage);
- }
- bool NetworkServiceNetworkDelegate::OnCanUseReportingClient(
- const url::Origin& origin,
- const GURL& endpoint) const {
- return network_context_->cookie_manager()
- ->cookie_settings()
- .IsFullCookieAccessAllowed(origin.GetURL(), origin.GetURL(),
- QueryReason::kSiteStorage);
- }
- int NetworkServiceNetworkDelegate::HandleClearSiteDataHeader(
- net::URLRequest* request,
- net::CompletionOnceCallback callback,
- const net::HttpResponseHeaders* original_response_headers) {
- DCHECK(request);
- if (!original_response_headers)
- return net::OK;
- URLLoader* url_loader = URLLoader::ForRequest(*request);
- if (!url_loader)
- return net::OK;
- auto* url_loader_network_observer =
- url_loader->GetURLLoaderNetworkServiceObserver();
- if (!url_loader_network_observer)
- return net::OK;
- std::string header_value;
- if (!original_response_headers->GetNormalizedHeader(kClearSiteDataHeader,
- &header_value)) {
- return net::OK;
- }
- url_loader_network_observer->OnClearSiteData(
- request->url(), header_value, request->load_flags(),
- net::CookiePartitionKey::FromNetworkIsolationKey(
- request->isolation_info().network_isolation_key()),
- base::BindOnce(&NetworkServiceNetworkDelegate::FinishedClearSiteData,
- weak_ptr_factory_.GetWeakPtr(), request->GetWeakPtr(),
- std::move(callback)));
- return net::ERR_IO_PENDING;
- }
- void NetworkServiceNetworkDelegate::FinishedClearSiteData(
- base::WeakPtr<net::URLRequest> request,
- net::CompletionOnceCallback callback) {
- if (request)
- std::move(callback).Run(net::OK);
- }
- void NetworkServiceNetworkDelegate::FinishedCanSendReportingReports(
- base::OnceCallback<void(std::set<url::Origin>)> result_callback,
- const std::vector<url::Origin>& origins) {
- std::set<url::Origin> origin_set(origins.begin(), origins.end());
- std::move(result_callback).Run(origin_set);
- }
- void NetworkServiceNetworkDelegate::ForwardProxyErrors(int net_error) {
- if (!proxy_error_client_)
- return;
- // TODO(https://crbug.com/876848): Provide justification for the currently
- // enumerated errors.
- switch (net_error) {
- case net::ERR_PROXY_AUTH_UNSUPPORTED:
- case net::ERR_PROXY_CONNECTION_FAILED:
- case net::ERR_TUNNEL_CONNECTION_FAILED:
- proxy_error_client_->OnRequestMaybeFailedDueToProxySettings(net_error);
- break;
- }
- }
- } // namespace network
|