1 // Copyright (c) 2012 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 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
6
7 #include "content/renderer/loader/resource_dispatcher.h"
8
9 #include <utility>
10
11 #include "base/atomic_sequence_num.h"
12 #include "base/bind.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/alias.h"
15 #include "base/files/file_path.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/rand_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/task/post_task.h"
21 #include "base/task/thread_pool.h"
22 #include "base/time/time.h"
23 #include "build/build_config.h"
24 #include "content/common/inter_process_time_ticks_converter.h"
25 #include "content/common/navigation_params.h"
26 #include "content/public/renderer/request_peer.h"
27 #include "content/public/renderer/resource_dispatcher_delegate.h"
28 #include "content/renderer/loader/sync_load_context.h"
29 #include "content/renderer/loader/url_loader_client_impl.h"
30 #include "content/renderer/render_frame_impl.h"
31 #include "content/renderer/render_thread_impl.h"
32 #include "net/base/load_flags.h"
33 #include "net/base/net_errors.h"
34 #include "net/base/request_priority.h"
35 #include "net/http/http_response_headers.h"
36 #include "net/url_request/referrer_policy.h"
37 #include "services/network/public/cpp/features.h"
38 #include "services/network/public/cpp/resource_request.h"
39 #include "services/network/public/cpp/url_loader_completion_status.h"
40 #include "services/network/public/mojom/fetch_api.mojom.h"
41 #include "services/network/public/mojom/url_response_head.mojom.h"
42 #include "third_party/blink/public/common/client_hints/client_hints.h"
43 #include "third_party/blink/public/common/loader/network_utils.h"
44 #include "third_party/blink/public/common/loader/referrer_utils.h"
45 #include "third_party/blink/public/common/loader/resource_type_util.h"
46 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
47 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
48 #include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
49 #include "third_party/blink/public/platform/sync_load_response.h"
50
51 namespace content {
52
53 namespace {
54
55 // Converts |time| from a remote to local TimeTicks, overwriting the original
56 // value.
RemoteToLocalTimeTicks(const InterProcessTimeTicksConverter & converter,base::TimeTicks * time)57 void RemoteToLocalTimeTicks(
58 const InterProcessTimeTicksConverter& converter,
59 base::TimeTicks* time) {
60 RemoteTimeTicks remote_time = RemoteTimeTicks::FromTimeTicks(*time);
61 *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
62 }
63
CheckSchemeForReferrerPolicy(const network::ResourceRequest & request)64 void CheckSchemeForReferrerPolicy(const network::ResourceRequest& request) {
65 if ((request.referrer_policy ==
66 blink::ReferrerUtils::GetDefaultNetReferrerPolicy() ||
67 request.referrer_policy ==
68 net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE) &&
69 request.referrer.SchemeIsCryptographic() &&
70 !url::Origin::Create(request.url).opaque() &&
71 !blink::network_utils::IsOriginSecure(request.url)) {
72 LOG(FATAL) << "Trying to send secure referrer for insecure request "
73 << "without an appropriate referrer policy.\n"
74 << "URL = " << request.url << "\n"
75 << "URL's Origin = "
76 << url::Origin::Create(request.url).Serialize() << "\n"
77 << "Referrer = " << request.referrer;
78 }
79 }
80
GetInitialRequestID()81 int GetInitialRequestID() {
82 // Starting with a random number speculatively avoids RDH_INVALID_REQUEST_ID
83 // which are assumed to have been caused by restarting RequestID at 0 when
84 // restarting a renderer after a crash - this would cause collisions if
85 // requests from the previously crashed renderer are still active. See
86 // https://crbug.com/614281#c61 for more details about this hypothesis.
87 //
88 // To avoid increasing the likelyhood of overflowing the range of available
89 // RequestIDs, kMax is set to a relatively low value of 2^20 (rather than
90 // to something higher like 2^31).
91 const int kMin = 0;
92 const int kMax = 1 << 20;
93 return base::RandInt(kMin, kMax);
94 }
95
96 // Determines if the loader should be restarted on a redirect using
97 // blink::ThrottlingURLLoader::FollowRedirectForcingRestart.
RedirectRequiresLoaderRestart(const GURL & original_url,const GURL & redirect_url)98 bool RedirectRequiresLoaderRestart(const GURL& original_url,
99 const GURL& redirect_url) {
100 // Restart is needed if the URL is no longer handled by network service.
101 if (blink::network_utils::IsURLHandledByNetworkService(original_url))
102 return !blink::network_utils::IsURLHandledByNetworkService(redirect_url);
103
104 // If URL wasn't originally handled by network service, restart is needed if
105 // schemes are different.
106 return original_url.scheme_piece() != redirect_url.scheme_piece();
107 }
108
109 } // namespace
110
111 // static
MakeRequestID()112 int ResourceDispatcher::MakeRequestID() {
113 // NOTE: The resource_dispatcher_host also needs probably unique
114 // request_ids, so they count down from -2 (-1 is a special "we're
115 // screwed value"), while the renderer process counts up.
116 static const int kInitialRequestID = GetInitialRequestID();
117 static base::AtomicSequenceNumber sequence;
118 return kInitialRequestID + sequence.GetNext();
119 }
120
ResourceDispatcher()121 ResourceDispatcher::ResourceDispatcher() : delegate_(nullptr) {}
122
~ResourceDispatcher()123 ResourceDispatcher::~ResourceDispatcher() {
124 }
125
126 ResourceDispatcher::PendingRequestInfo*
GetPendingRequestInfo(int request_id)127 ResourceDispatcher::GetPendingRequestInfo(int request_id) {
128 auto it = pending_requests_.find(request_id);
129 if (it == pending_requests_.end())
130 return nullptr;
131 return it->second.get();
132 }
133
OnUploadProgress(int request_id,int64_t position,int64_t size)134 void ResourceDispatcher::OnUploadProgress(int request_id,
135 int64_t position,
136 int64_t size) {
137 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
138 if (!request_info)
139 return;
140
141 request_info->peer->OnUploadProgress(position, size);
142 }
143
OnReceivedResponse(int request_id,network::mojom::URLResponseHeadPtr response_head)144 void ResourceDispatcher::OnReceivedResponse(
145 int request_id,
146 network::mojom::URLResponseHeadPtr response_head) {
147 TRACE_EVENT0("loading", "ResourceDispatcher::OnReceivedResponse");
148 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
149 if (!request_info)
150 return;
151 request_info->local_response_start = base::TimeTicks::Now();
152 request_info->remote_request_start = response_head->load_timing.request_start;
153 // Now that response_start has been set, we can properly set the TimeTicks in
154 // the URLResponseHead.
155 ToLocalURLResponseHead(*request_info, *response_head);
156 request_info->load_timing_info = response_head->load_timing;
157 if (delegate_) {
158 std::unique_ptr<RequestPeer> new_peer = delegate_->OnReceivedResponse(
159 std::move(request_info->peer), response_head->mime_type,
160 request_info->url);
161 DCHECK(new_peer);
162 request_info->peer = std::move(new_peer);
163 }
164
165 request_info->peer->OnReceivedResponse(response_head.Clone());
166 if (!GetPendingRequestInfo(request_id))
167 return;
168
169 request_info->resource_load_info_notifier_wrapper
170 ->NotifyResourceResponseReceived(std::move(response_head),
171 request_info->previews_state);
172 }
173
OnReceivedCachedMetadata(int request_id,mojo_base::BigBuffer data)174 void ResourceDispatcher::OnReceivedCachedMetadata(int request_id,
175 mojo_base::BigBuffer data) {
176 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
177 if (!request_info)
178 return;
179
180 if (data.size()) {
181 request_info->peer->OnReceivedCachedMetadata(std::move(data));
182 }
183 }
184
OnStartLoadingResponseBody(int request_id,mojo::ScopedDataPipeConsumerHandle body)185 void ResourceDispatcher::OnStartLoadingResponseBody(
186 int request_id,
187 mojo::ScopedDataPipeConsumerHandle body) {
188 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
189 if (!request_info)
190 return;
191
192 request_info->peer->OnStartLoadingResponseBody(std::move(body));
193 }
194
OnReceivedRedirect(int request_id,const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr response_head,scoped_refptr<base::SingleThreadTaskRunner> task_runner)195 void ResourceDispatcher::OnReceivedRedirect(
196 int request_id,
197 const net::RedirectInfo& redirect_info,
198 network::mojom::URLResponseHeadPtr response_head,
199 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
200 TRACE_EVENT0("loading", "ResourceDispatcher::OnReceivedRedirect");
201 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
202 if (!request_info)
203 return;
204 if (!request_info->url_loader && request_info->should_follow_redirect) {
205 // This is a redirect that synchronously came as the loader is being
206 // constructed, due to a URLLoaderThrottle that changed the starting
207 // URL. Handle this in a posted task, as we don't have the loader
208 // pointer yet.
209 base::ThreadTaskRunnerHandle::Get()->PostTask(
210 FROM_HERE,
211 base::BindOnce(&ResourceDispatcher::OnReceivedRedirect,
212 weak_factory_.GetWeakPtr(), request_id, redirect_info,
213 std::move(response_head), task_runner));
214 return;
215 }
216
217 request_info->local_response_start = base::TimeTicks::Now();
218 request_info->remote_request_start = response_head->load_timing.request_start;
219 request_info->redirect_requires_loader_restart =
220 RedirectRequiresLoaderRestart(request_info->response_url,
221 redirect_info.new_url);
222
223 ToLocalURLResponseHead(*request_info, *response_head);
224 std::vector<std::string> removed_headers;
225 if (request_info->peer->OnReceivedRedirect(
226 redirect_info, response_head.Clone(), &removed_headers)) {
227 // Double-check if the request is still around. The call above could
228 // potentially remove it.
229 request_info = GetPendingRequestInfo(request_id);
230 if (!request_info)
231 return;
232 // TODO(yoav): If request_info doesn't change above, we could avoid this
233 // copy.
234 request_info->removed_headers = removed_headers;
235
236 request_info->response_url = redirect_info.new_url;
237 request_info->has_pending_redirect = true;
238 request_info->resource_load_info_notifier_wrapper
239 ->NotifyResourceRedirectReceived(redirect_info,
240 std::move(response_head));
241
242 if (request_info->is_deferred ==
243 blink::WebURLLoader::DeferType::kNotDeferred)
244 FollowPendingRedirect(request_info);
245 } else {
246 Cancel(request_id, std::move(task_runner));
247 }
248 }
249
FollowPendingRedirect(PendingRequestInfo * request_info)250 void ResourceDispatcher::FollowPendingRedirect(
251 PendingRequestInfo* request_info) {
252 if (request_info->has_pending_redirect &&
253 request_info->should_follow_redirect) {
254 request_info->has_pending_redirect = false;
255 // net::URLRequest clears its request_start on redirect, so should we.
256 request_info->local_request_start = base::TimeTicks::Now();
257 // Redirect URL may not be handled by the network service, so force a
258 // restart in case another URLLoaderFactory should handle the URL.
259 if (request_info->redirect_requires_loader_restart) {
260 request_info->url_loader->FollowRedirectForcingRestart();
261 } else {
262 request_info->url_loader->FollowRedirect(
263 request_info->removed_headers, {} /* modified_headers */,
264 {} /* modified_cors_exempt_headers */);
265 }
266 }
267 }
268
OnRequestComplete(int request_id,const network::URLLoaderCompletionStatus & status)269 void ResourceDispatcher::OnRequestComplete(
270 int request_id,
271 const network::URLLoaderCompletionStatus& status) {
272 TRACE_EVENT0("loading", "ResourceDispatcher::OnRequestComplete");
273
274 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
275 if (!request_info)
276 return;
277 request_info->net_error = status.error_code;
278
279 request_info->resource_load_info_notifier_wrapper
280 ->NotifyResourceLoadCompleted(status);
281
282 RequestPeer* peer = request_info->peer.get();
283
284 if (delegate_) {
285 delegate_->OnRequestComplete();
286 }
287
288 network::URLLoaderCompletionStatus renderer_status(status);
289 if (status.completion_time.is_null()) {
290 // No completion timestamp is provided, leave it as is.
291 } else if (request_info->remote_request_start.is_null() ||
292 request_info->load_timing_info.request_start.is_null()) {
293 // We cannot convert the remote time to a local time, let's use the current
294 // timestamp. This happens when
295 // - We get an error before OnReceivedRedirect or OnReceivedResponse is
296 // called, or
297 // - Somehow such a timestamp was missing in the LoadTimingInfo.
298 renderer_status.completion_time = base::TimeTicks::Now();
299 } else {
300 // We have already converted the request start timestamp, let's use that
301 // conversion information.
302 // Note: We cannot create a InterProcessTimeTicksConverter with
303 // (local_request_start, now, remote_request_start, remote_completion_time)
304 // as that may result in inconsistent timestamps.
305 renderer_status.completion_time =
306 std::min(status.completion_time - request_info->remote_request_start +
307 request_info->load_timing_info.request_start,
308 base::TimeTicks::Now());
309 }
310 // The request ID will be removed from our pending list in the destructor.
311 // Normally, dispatching this message causes the reference-counted request to
312 // die immediately.
313 // TODO(kinuko): Revisit here. This probably needs to call request_info->peer
314 // but the past attempt to change it seems to have caused crashes.
315 // (crbug.com/547047)
316 peer->OnCompletedRequest(renderer_status);
317 }
318
RemovePendingRequest(int request_id,scoped_refptr<base::SingleThreadTaskRunner> task_runner)319 bool ResourceDispatcher::RemovePendingRequest(
320 int request_id,
321 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
322 auto it = pending_requests_.find(request_id);
323 if (it == pending_requests_.end())
324 return false;
325
326 PendingRequestInfo* info = it->second.get();
327 if (info->net_error == net::ERR_IO_PENDING) {
328 info->net_error = net::ERR_ABORTED;
329 info->resource_load_info_notifier_wrapper->NotifyResourceLoadCanceled(
330 info->net_error);
331 }
332
333 // Cancel loading.
334 info->url_loader = nullptr;
335 // Clear URLLoaderClient to stop receiving further Mojo IPC from the browser
336 // process.
337 info->url_loader_client = nullptr;
338
339 // Always delete the pending_request asyncly so that cancelling the request
340 // doesn't delete the request context info while its response is still being
341 // handled.
342 task_runner->DeleteSoon(FROM_HERE, it->second.release());
343 pending_requests_.erase(it);
344
345 return true;
346 }
347
Cancel(int request_id,scoped_refptr<base::SingleThreadTaskRunner> task_runner)348 void ResourceDispatcher::Cancel(
349 int request_id,
350 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
351 auto it = pending_requests_.find(request_id);
352 if (it == pending_requests_.end()) {
353 DLOG(ERROR) << "unknown request";
354 return;
355 }
356
357 // Cancel the request if it didn't complete, and clean it up so the bridge
358 // will receive no more messages.
359 RemovePendingRequest(request_id, std::move(task_runner));
360 }
361
SetDefersLoading(int request_id,blink::WebURLLoader::DeferType value)362 void ResourceDispatcher::SetDefersLoading(
363 int request_id,
364 blink::WebURLLoader::DeferType value) {
365 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
366 if (!request_info) {
367 DLOG(ERROR) << "unknown request";
368 return;
369 }
370 if (value != blink::WebURLLoader::DeferType::kNotDeferred) {
371 request_info->is_deferred = value;
372 request_info->url_loader_client->SetDefersLoading(value);
373 } else if (request_info->is_deferred !=
374 blink::WebURLLoader::DeferType::kNotDeferred) {
375 request_info->is_deferred = blink::WebURLLoader::DeferType::kNotDeferred;
376 request_info->url_loader_client->SetDefersLoading(
377 blink::WebURLLoader::DeferType::kNotDeferred);
378
379 FollowPendingRedirect(request_info);
380 }
381 }
382
DidChangePriority(int request_id,net::RequestPriority new_priority,int intra_priority_value)383 void ResourceDispatcher::DidChangePriority(int request_id,
384 net::RequestPriority new_priority,
385 int intra_priority_value) {
386 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
387 if (!request_info) {
388 DLOG(ERROR) << "unknown request";
389 return;
390 }
391
392 request_info->url_loader->SetPriority(new_priority, intra_priority_value);
393 }
394
OnTransferSizeUpdated(int request_id,int32_t transfer_size_diff)395 void ResourceDispatcher::OnTransferSizeUpdated(int request_id,
396 int32_t transfer_size_diff) {
397 DCHECK_GT(transfer_size_diff, 0);
398 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
399 if (!request_info)
400 return;
401
402 // TODO(yhirano): Consider using int64_t in
403 // RequestPeer::OnTransferSizeUpdated.
404 request_info->peer->OnTransferSizeUpdated(transfer_size_diff);
405 if (!GetPendingRequestInfo(request_id))
406 return;
407 request_info->resource_load_info_notifier_wrapper
408 ->NotifyResourceTransferSizeUpdated(transfer_size_diff);
409 }
410
EvictFromBackForwardCache(blink::mojom::RendererEvictionReason reason,int request_id)411 void ResourceDispatcher::EvictFromBackForwardCache(
412 blink::mojom::RendererEvictionReason reason,
413 int request_id) {
414 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
415 if (!request_info)
416 return;
417
418 return request_info->peer->EvictFromBackForwardCache(reason);
419 }
420
SetCorsExemptHeaderList(const std::vector<std::string> & list)421 void ResourceDispatcher::SetCorsExemptHeaderList(
422 const std::vector<std::string>& list) {
423 cors_exempt_header_list_ = list;
424 }
425
PendingRequestInfo(std::unique_ptr<RequestPeer> peer,network::mojom::RequestDestination request_destination,int render_frame_id,const GURL & request_url,std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> resource_load_info_notifier_wrapper)426 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
427 std::unique_ptr<RequestPeer> peer,
428 network::mojom::RequestDestination request_destination,
429 int render_frame_id,
430 const GURL& request_url,
431 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
432 resource_load_info_notifier_wrapper)
433 : peer(std::move(peer)),
434 request_destination(request_destination),
435 render_frame_id(render_frame_id),
436 url(request_url),
437 response_url(request_url),
438 local_request_start(base::TimeTicks::Now()),
439 resource_load_info_notifier_wrapper(
440 std::move(resource_load_info_notifier_wrapper)) {}
441
~PendingRequestInfo()442 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
443 }
444
StartSync(std::unique_ptr<network::ResourceRequest> request,int routing_id,const net::NetworkTrafficAnnotationTag & traffic_annotation,uint32_t loader_options,blink::SyncLoadResponse * response,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,base::TimeDelta timeout,mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,std::unique_ptr<RequestPeer> peer,std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> resource_load_info_notifier_wrapper)445 void ResourceDispatcher::StartSync(
446 std::unique_ptr<network::ResourceRequest> request,
447 int routing_id,
448 const net::NetworkTrafficAnnotationTag& traffic_annotation,
449 uint32_t loader_options,
450 blink::SyncLoadResponse* response,
451 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
452 std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
453 base::TimeDelta timeout,
454 mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
455 std::unique_ptr<RequestPeer> peer,
456 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
457 resource_load_info_notifier_wrapper) {
458 CheckSchemeForReferrerPolicy(*request);
459
460 DCHECK(loader_options & network::mojom::kURLLoadOptionSynchronous);
461 DCHECK(request->load_flags & net::LOAD_IGNORE_LIMITS);
462
463 std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory =
464 url_loader_factory->Clone();
465 base::WaitableEvent redirect_or_response_event(
466 base::WaitableEvent::ResetPolicy::MANUAL,
467 base::WaitableEvent::InitialState::NOT_SIGNALED);
468
469 // Prepare the configured throttles for use on a separate thread.
470 for (const auto& throttle : throttles)
471 throttle->DetachFromCurrentSequence();
472
473 // A task is posted to a separate thread to execute the request so that
474 // this thread may block on a waitable event. It is safe to pass raw
475 // pointers to on-stack objects as this stack frame will
476 // survive until the request is complete.
477 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
478 base::ThreadPool::CreateSingleThreadTaskRunner({});
479 SyncLoadContext* context_for_redirect = nullptr;
480 task_runner->PostTask(
481 FROM_HERE,
482 base::BindOnce(
483 &SyncLoadContext::StartAsyncWithWaitableEvent, std::move(request),
484 routing_id, task_runner, traffic_annotation, loader_options,
485 std::move(pending_factory), std::move(throttles),
486 base::Unretained(response), base::Unretained(&context_for_redirect),
487 base::Unretained(&redirect_or_response_event),
488 base::Unretained(terminate_sync_load_event_), timeout,
489 std::move(download_to_blob_registry), cors_exempt_header_list_,
490 std::move(resource_load_info_notifier_wrapper)));
491
492 // redirect_or_response_event will signal when each redirect completes, and
493 // when the final response is complete.
494 redirect_or_response_event.Wait();
495
496 while (context_for_redirect) {
497 DCHECK(response->redirect_info);
498 bool follow_redirect = peer->OnReceivedRedirect(
499 *response->redirect_info, response->head.Clone(),
500 nullptr /* removed_headers */);
501 redirect_or_response_event.Reset();
502 if (follow_redirect) {
503 task_runner->PostTask(
504 FROM_HERE, base::BindOnce(&SyncLoadContext::FollowRedirect,
505 base::Unretained(context_for_redirect)));
506 } else {
507 task_runner->PostTask(
508 FROM_HERE, base::BindOnce(&SyncLoadContext::CancelRedirect,
509 base::Unretained(context_for_redirect)));
510 }
511 redirect_or_response_event.Wait();
512 }
513 }
514
StartAsync(std::unique_ptr<network::ResourceRequest> request,int routing_id,scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,const net::NetworkTrafficAnnotationTag & traffic_annotation,uint32_t loader_options,std::unique_ptr<RequestPeer> peer,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> resource_load_info_notifier_wrapper)515 int ResourceDispatcher::StartAsync(
516 std::unique_ptr<network::ResourceRequest> request,
517 int routing_id,
518 scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
519 const net::NetworkTrafficAnnotationTag& traffic_annotation,
520 uint32_t loader_options,
521 std::unique_ptr<RequestPeer> peer,
522 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
523 std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
524 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
525 resource_load_info_notifier_wrapper) {
526 CheckSchemeForReferrerPolicy(*request);
527
528 #if defined(OS_ANDROID)
529 // Main frame shouldn't come here.
530 DCHECK(!(request->is_main_frame &&
531 blink::IsRequestDestinationFrame(request->destination)));
532 if (request->has_user_gesture) {
533 resource_load_info_notifier_wrapper->NotifyUpdateUserGestureCarryoverInfo();
534 }
535 #endif
536
537 // Compute a unique request_id for this renderer process.
538 int request_id = MakeRequestID();
539 pending_requests_[request_id] = std::make_unique<PendingRequestInfo>(
540 std::move(peer), request->destination, request->render_frame_id,
541 request->url, std::move(resource_load_info_notifier_wrapper));
542 PendingRequestInfo* pending_request = pending_requests_[request_id].get();
543
544 pending_request->resource_load_info_notifier_wrapper
545 ->NotifyResourceLoadInitiated(
546 request_id, request->url, request->method, request->referrer,
547 pending_request->request_destination, request->priority);
548
549 pending_request->previews_state = request->previews_state;
550
551 std::unique_ptr<URLLoaderClientImpl> client(new URLLoaderClientImpl(
552 request_id, this, loading_task_runner,
553 url_loader_factory->BypassRedirectChecks(), request->url));
554
555 std::unique_ptr<blink::ThrottlingURLLoader> url_loader =
556 blink::ThrottlingURLLoader::CreateLoaderAndStart(
557 std::move(url_loader_factory), std::move(throttles), routing_id,
558 request_id, loader_options, request.get(), client.get(),
559 traffic_annotation, std::move(loading_task_runner),
560 base::make_optional(cors_exempt_header_list_));
561 pending_request->url_loader = std::move(url_loader);
562 pending_request->url_loader_client = std::move(client);
563
564 return request_id;
565 }
566
ToLocalURLResponseHead(const PendingRequestInfo & request_info,network::mojom::URLResponseHead & response_head) const567 void ResourceDispatcher::ToLocalURLResponseHead(
568 const PendingRequestInfo& request_info,
569 network::mojom::URLResponseHead& response_head) const {
570 if (base::TimeTicks::IsConsistentAcrossProcesses() ||
571 request_info.local_request_start.is_null() ||
572 request_info.local_response_start.is_null() ||
573 response_head.request_start.is_null() ||
574 response_head.response_start.is_null() ||
575 response_head.load_timing.request_start.is_null()) {
576 return;
577 }
578 InterProcessTimeTicksConverter converter(
579 LocalTimeTicks::FromTimeTicks(request_info.local_request_start),
580 LocalTimeTicks::FromTimeTicks(request_info.local_response_start),
581 RemoteTimeTicks::FromTimeTicks(response_head.request_start),
582 RemoteTimeTicks::FromTimeTicks(response_head.response_start));
583
584 net::LoadTimingInfo* load_timing = &response_head.load_timing;
585 RemoteToLocalTimeTicks(converter, &load_timing->request_start);
586 RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_start);
587 RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_end);
588 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_start);
589 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_end);
590 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_start);
591 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_end);
592 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_start);
593 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_end);
594 RemoteToLocalTimeTicks(converter, &load_timing->send_start);
595 RemoteToLocalTimeTicks(converter, &load_timing->send_end);
596 RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_start);
597 RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end);
598 RemoteToLocalTimeTicks(converter, &load_timing->push_start);
599 RemoteToLocalTimeTicks(converter, &load_timing->push_end);
600 RemoteToLocalTimeTicks(converter, &load_timing->service_worker_start_time);
601 RemoteToLocalTimeTicks(converter, &load_timing->service_worker_ready_time);
602 RemoteToLocalTimeTicks(converter, &load_timing->service_worker_fetch_start);
603 RemoteToLocalTimeTicks(converter,
604 &load_timing->service_worker_respond_with_settled);
605 }
606
607 } // namespace content
608