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