1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/network/network_service_network_delegate.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/debug/dump_without_crashing.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "components/domain_reliability/monitor.h"
14 #include "net/base/isolation_info.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/net_errors.h"
17 #include "net/url_request/url_request.h"
18 #include "services/network/cookie_manager.h"
19 #include "services/network/network_context.h"
20 #include "services/network/network_service.h"
21 #include "services/network/network_service_proxy_delegate.h"
22 #include "services/network/pending_callback_chain.h"
23 #include "services/network/public/cpp/features.h"
24 #include "services/network/url_loader.h"
25 #include "url/gurl.h"
26
27 #if !defined(OS_IOS)
28 #include "services/network/websocket.h"
29 #endif
30
31 namespace network {
32
33 namespace {
34
35 const char kClearSiteDataHeader[] = "Clear-Site-Data";
36
37 } // anonymous namespace
38
NetworkServiceNetworkDelegate(bool enable_referrers,bool validate_referrer_policy_on_initial_request,mojo::PendingRemote<mojom::ProxyErrorClient> proxy_error_client_remote,NetworkContext * network_context)39 NetworkServiceNetworkDelegate::NetworkServiceNetworkDelegate(
40 bool enable_referrers,
41 bool validate_referrer_policy_on_initial_request,
42 mojo::PendingRemote<mojom::ProxyErrorClient> proxy_error_client_remote,
43 NetworkContext* network_context)
44 : enable_referrers_(enable_referrers),
45 validate_referrer_policy_on_initial_request_(
46 validate_referrer_policy_on_initial_request),
47 network_context_(network_context) {
48 if (proxy_error_client_remote)
49 proxy_error_client_.Bind(std::move(proxy_error_client_remote));
50 }
51
52 NetworkServiceNetworkDelegate::~NetworkServiceNetworkDelegate() = default;
53
MaybeTruncateReferrer(net::URLRequest * const request,const GURL & effective_url)54 void NetworkServiceNetworkDelegate::MaybeTruncateReferrer(
55 net::URLRequest* const request,
56 const GURL& effective_url) {
57 if (!enable_referrers_) {
58 request->SetReferrer(std::string());
59 request->set_referrer_policy(net::URLRequest::NO_REFERRER);
60 return;
61 }
62
63 if (base::FeatureList::IsEnabled(
64 features::kCapReferrerToOriginOnCrossOrigin)) {
65 url::Origin destination_origin = url::Origin::Create(effective_url);
66 url::Origin source_origin = url::Origin::Create(GURL(request->referrer()));
67 if (!destination_origin.IsSameOriginWith(source_origin))
68 request->SetReferrer(source_origin.GetURL().spec());
69 }
70 }
71
OnBeforeURLRequest(net::URLRequest * request,net::CompletionOnceCallback callback,GURL * new_url)72 int NetworkServiceNetworkDelegate::OnBeforeURLRequest(
73 net::URLRequest* request,
74 net::CompletionOnceCallback callback,
75 GURL* new_url) {
76 DCHECK(request);
77
78 auto* const loader = URLLoader::ForRequest(*request);
79 const GURL* effective_url = nullptr;
80 if (loader && loader->new_redirect_url()) {
81 DCHECK(new_url);
82 *new_url = loader->new_redirect_url().value();
83 effective_url = new_url;
84 } else {
85 effective_url = &request->url();
86 }
87
88 MaybeTruncateReferrer(request, *effective_url);
89
90 NetworkService* network_service = network_context_->network_service();
91 if (network_service)
92 network_service->OnBeforeURLRequest();
93
94 if (!loader)
95 return net::OK;
96
97 if (network_service) {
98 loader->SetAllowReportingRawHeaders(network_service->HasRawHeadersAccess(
99 loader->GetProcessId(), *effective_url));
100 }
101 return net::OK;
102 }
103
OnBeforeStartTransaction(net::URLRequest * request,net::CompletionOnceCallback callback,net::HttpRequestHeaders * headers)104 int NetworkServiceNetworkDelegate::OnBeforeStartTransaction(
105 net::URLRequest* request,
106 net::CompletionOnceCallback callback,
107 net::HttpRequestHeaders* headers) {
108 URLLoader* url_loader = URLLoader::ForRequest(*request);
109 if (url_loader)
110 return url_loader->OnBeforeStartTransaction(std::move(callback), headers);
111
112 #if !defined(OS_IOS)
113 WebSocket* web_socket = WebSocket::ForRequest(*request);
114 if (web_socket)
115 return web_socket->OnBeforeStartTransaction(std::move(callback), headers);
116 #endif // !defined(OS_IOS)
117
118 return net::OK;
119 }
120
OnHeadersReceived(net::URLRequest * request,net::CompletionOnceCallback callback,const net::HttpResponseHeaders * original_response_headers,scoped_refptr<net::HttpResponseHeaders> * override_response_headers,const net::IPEndPoint & endpoint,base::Optional<GURL> * preserve_fragment_on_redirect_url)121 int NetworkServiceNetworkDelegate::OnHeadersReceived(
122 net::URLRequest* request,
123 net::CompletionOnceCallback callback,
124 const net::HttpResponseHeaders* original_response_headers,
125 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
126 const net::IPEndPoint& endpoint,
127 base::Optional<GURL>* preserve_fragment_on_redirect_url) {
128 auto chain = base::MakeRefCounted<PendingCallbackChain>(std::move(callback));
129 URLLoader* url_loader = URLLoader::ForRequest(*request);
130 if (url_loader) {
131 chain->AddResult(url_loader->OnHeadersReceived(
132 chain->CreateCallback(), original_response_headers,
133 override_response_headers, endpoint,
134 preserve_fragment_on_redirect_url));
135 }
136
137 #if !defined(OS_IOS)
138 WebSocket* web_socket = WebSocket::ForRequest(*request);
139 if (web_socket) {
140 chain->AddResult(web_socket->OnHeadersReceived(
141 chain->CreateCallback(), original_response_headers,
142 override_response_headers, preserve_fragment_on_redirect_url));
143 }
144 #endif // !defined(OS_IOS)
145
146 chain->AddResult(HandleClearSiteDataHeader(request, chain->CreateCallback(),
147 original_response_headers));
148
149 return chain->GetResult();
150 }
151
OnBeforeRedirect(net::URLRequest * request,const GURL & new_location)152 void NetworkServiceNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
153 const GURL& new_location) {
154 if (network_context_->domain_reliability_monitor())
155 network_context_->domain_reliability_monitor()->OnBeforeRedirect(request);
156 }
157
OnResponseStarted(net::URLRequest * request,int net_error)158 void NetworkServiceNetworkDelegate::OnResponseStarted(net::URLRequest* request,
159 int net_error) {
160 ForwardProxyErrors(net_error);
161 }
162
OnCompleted(net::URLRequest * request,bool started,int net_error)163 void NetworkServiceNetworkDelegate::OnCompleted(net::URLRequest* request,
164 bool started,
165 int net_error) {
166 // TODO(mmenke): Once the network service ships on all platforms, can move
167 // this logic into URLLoader's completion method.
168 DCHECK_NE(net::ERR_IO_PENDING, net_error);
169
170 if (network_context_->domain_reliability_monitor()) {
171 network_context_->domain_reliability_monitor()->OnCompleted(
172 request, started, net_error);
173 }
174
175 ForwardProxyErrors(net_error);
176 }
177
OnPACScriptError(int line_number,const base::string16 & error)178 void NetworkServiceNetworkDelegate::OnPACScriptError(
179 int line_number,
180 const base::string16& error) {
181 if (!proxy_error_client_)
182 return;
183
184 proxy_error_client_->OnPACScriptError(line_number, base::UTF16ToUTF8(error));
185 }
186
OnCanGetCookies(const net::URLRequest & request,const net::CookieList & cookie_list,bool allowed_from_caller)187 bool NetworkServiceNetworkDelegate::OnCanGetCookies(
188 const net::URLRequest& request,
189 const net::CookieList& cookie_list,
190 bool allowed_from_caller) {
191 bool allowed =
192 allowed_from_caller &&
193 network_context_->cookie_manager()
194 ->cookie_settings()
195 .IsCookieAccessAllowed(request.url(),
196 request.site_for_cookies().RepresentativeUrl(),
197 request.isolation_info()
198 .network_isolation_key()
199 .GetTopFrameOrigin());
200
201 if (!allowed)
202 return false;
203
204 URLLoader* url_loader = URLLoader::ForRequest(request);
205 if (url_loader)
206 return url_loader->AllowCookies(request.url(), request.site_for_cookies());
207 #if !defined(OS_IOS)
208 WebSocket* web_socket = WebSocket::ForRequest(request);
209 if (web_socket)
210 return web_socket->AllowCookies(request.url());
211 #endif // !defined(OS_IOS)
212 return true;
213 }
214
OnCanSetCookie(const net::URLRequest & request,const net::CanonicalCookie & cookie,net::CookieOptions * options,bool allowed_from_caller)215 bool NetworkServiceNetworkDelegate::OnCanSetCookie(
216 const net::URLRequest& request,
217 const net::CanonicalCookie& cookie,
218 net::CookieOptions* options,
219 bool allowed_from_caller) {
220 bool allowed =
221 allowed_from_caller &&
222 network_context_->cookie_manager()
223 ->cookie_settings()
224 .IsCookieAccessAllowed(request.url(),
225 request.site_for_cookies().RepresentativeUrl(),
226 request.isolation_info().top_frame_origin());
227 if (!allowed)
228 return false;
229 URLLoader* url_loader = URLLoader::ForRequest(request);
230 if (url_loader)
231 return url_loader->AllowCookies(request.url(), request.site_for_cookies());
232 #if !defined(OS_IOS)
233 WebSocket* web_socket = WebSocket::ForRequest(request);
234 if (web_socket)
235 return web_socket->AllowCookies(request.url());
236 #endif // !defined(OS_IOS)
237 return true;
238 }
239
OnForcePrivacyMode(const GURL & url,const net::SiteForCookies & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin) const240 bool NetworkServiceNetworkDelegate::OnForcePrivacyMode(
241 const GURL& url,
242 const net::SiteForCookies& site_for_cookies,
243 const base::Optional<url::Origin>& top_frame_origin) const {
244 return !network_context_->cookie_manager()
245 ->cookie_settings()
246 .IsCookieAccessAllowed(url, site_for_cookies.RepresentativeUrl(),
247 top_frame_origin);
248 }
249
250 bool NetworkServiceNetworkDelegate::
OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest & request,const GURL & target_url,const GURL & referrer_url) const251 OnCancelURLRequestWithPolicyViolatingReferrerHeader(
252 const net::URLRequest& request,
253 const GURL& target_url,
254 const GURL& referrer_url) const {
255 // TODO(mmenke): Once the network service has shipped on all platforms,
256 // consider moving this logic into URLLoader, and removing this method from
257 // NetworkDelegate. Can just have a DCHECK in URLRequest instead.
258 if (!validate_referrer_policy_on_initial_request_)
259 return false;
260
261 LOG(ERROR) << "Cancelling request to " << target_url
262 << " with invalid referrer " << referrer_url;
263 // Record information to help debug issues like http://crbug.com/422871.
264 if (target_url.SchemeIsHTTPOrHTTPS()) {
265 auto referrer_policy = request.referrer_policy();
266 base::debug::Alias(&referrer_policy);
267 DEBUG_ALIAS_FOR_GURL(target_buf, target_url);
268 DEBUG_ALIAS_FOR_GURL(referrer_buf, referrer_url);
269 base::debug::DumpWithoutCrashing();
270 }
271 return true;
272 }
273
OnCanQueueReportingReport(const url::Origin & origin) const274 bool NetworkServiceNetworkDelegate::OnCanQueueReportingReport(
275 const url::Origin& origin) const {
276 return network_context_->cookie_manager()
277 ->cookie_settings()
278 .IsCookieAccessAllowed(origin.GetURL(), origin.GetURL());
279 }
280
OnCanSendReportingReports(std::set<url::Origin> origins,base::OnceCallback<void (std::set<url::Origin>)> result_callback) const281 void NetworkServiceNetworkDelegate::OnCanSendReportingReports(
282 std::set<url::Origin> origins,
283 base::OnceCallback<void(std::set<url::Origin>)> result_callback) const {
284 auto* client = network_context_->client();
285 if (!client) {
286 origins.clear();
287 std::move(result_callback).Run(std::move(origins));
288 return;
289 }
290
291 if (network_context_->SkipReportingPermissionCheck()) {
292 std::move(result_callback).Run(std::move(origins));
293 return;
294 }
295
296 std::vector<url::Origin> origin_vector;
297 std::copy(origins.begin(), origins.end(), std::back_inserter(origin_vector));
298 client->OnCanSendReportingReports(
299 origin_vector,
300 base::BindOnce(
301 &NetworkServiceNetworkDelegate::FinishedCanSendReportingReports,
302 weak_ptr_factory_.GetWeakPtr(), std::move(result_callback)));
303 }
304
OnCanSetReportingClient(const url::Origin & origin,const GURL & endpoint) const305 bool NetworkServiceNetworkDelegate::OnCanSetReportingClient(
306 const url::Origin& origin,
307 const GURL& endpoint) const {
308 return network_context_->cookie_manager()
309 ->cookie_settings()
310 .IsCookieAccessAllowed(origin.GetURL(), origin.GetURL());
311 }
312
OnCanUseReportingClient(const url::Origin & origin,const GURL & endpoint) const313 bool NetworkServiceNetworkDelegate::OnCanUseReportingClient(
314 const url::Origin& origin,
315 const GURL& endpoint) const {
316 return network_context_->cookie_manager()
317 ->cookie_settings()
318 .IsCookieAccessAllowed(origin.GetURL(), origin.GetURL());
319 }
320
HandleClearSiteDataHeader(net::URLRequest * request,net::CompletionOnceCallback callback,const net::HttpResponseHeaders * original_response_headers)321 int NetworkServiceNetworkDelegate::HandleClearSiteDataHeader(
322 net::URLRequest* request,
323 net::CompletionOnceCallback callback,
324 const net::HttpResponseHeaders* original_response_headers) {
325 DCHECK(request);
326 if (!original_response_headers || !network_context_->client())
327 return net::OK;
328
329 URLLoader* url_loader = URLLoader::ForRequest(*request);
330 if (!url_loader)
331 return net::OK;
332
333 std::string header_value;
334 if (!original_response_headers->GetNormalizedHeader(kClearSiteDataHeader,
335 &header_value)) {
336 return net::OK;
337 }
338
339 network_context_->client()->OnClearSiteData(
340 url_loader->GetProcessId(), url_loader->GetRenderFrameId(),
341 request->url(), header_value, request->load_flags(),
342 base::BindOnce(&NetworkServiceNetworkDelegate::FinishedClearSiteData,
343 weak_ptr_factory_.GetWeakPtr(), request->GetWeakPtr(),
344 std::move(callback)));
345
346 return net::ERR_IO_PENDING;
347 }
348
FinishedClearSiteData(base::WeakPtr<net::URLRequest> request,net::CompletionOnceCallback callback)349 void NetworkServiceNetworkDelegate::FinishedClearSiteData(
350 base::WeakPtr<net::URLRequest> request,
351 net::CompletionOnceCallback callback) {
352 if (request)
353 std::move(callback).Run(net::OK);
354 }
355
FinishedCanSendReportingReports(base::OnceCallback<void (std::set<url::Origin>)> result_callback,const std::vector<url::Origin> & origins)356 void NetworkServiceNetworkDelegate::FinishedCanSendReportingReports(
357 base::OnceCallback<void(std::set<url::Origin>)> result_callback,
358 const std::vector<url::Origin>& origins) {
359 std::set<url::Origin> origin_set(origins.begin(), origins.end());
360 std::move(result_callback).Run(origin_set);
361 }
362
ForwardProxyErrors(int net_error)363 void NetworkServiceNetworkDelegate::ForwardProxyErrors(int net_error) {
364 if (!proxy_error_client_)
365 return;
366
367 // TODO(https://crbug.com/876848): Provide justification for the currently
368 // enumerated errors.
369 switch (net_error) {
370 case net::ERR_PROXY_AUTH_UNSUPPORTED:
371 case net::ERR_PROXY_CONNECTION_FAILED:
372 case net::ERR_TUNNEL_CONNECTION_FAILED:
373 proxy_error_client_->OnRequestMaybeFailedDueToProxySettings(net_error);
374 break;
375 }
376 }
377
378 } // namespace network
379