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.
5 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
7 #include "content/child/resource_dispatcher.h"
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/debug/alias.h"
13 #include "base/debug/dump_without_crashing.h"
14 #include "base/files/file_path.h"
15 #include "base/memory/shared_memory.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/strings/string_util.h"
19 #include "content/child/request_extra_data.h"
20 #include "content/child/request_info.h"
21 #include "content/child/shared_memory_received_data_factory.h"
22 #include "content/child/site_isolation_policy.h"
23 #include "content/child/sync_load_response.h"
24 #include "content/child/threaded_data_provider.h"
25 #include "content/common/inter_process_time_ticks_converter.h"
26 #include "content/common/resource_messages.h"
27 #include "content/public/child/fixed_received_data.h"
28 #include "content/public/child/request_peer.h"
29 #include "content/public/child/resource_dispatcher_delegate.h"
30 #include "content/public/common/resource_response.h"
31 #include "content/public/common/resource_type.h"
32 #include "net/base/net_errors.h"
33 #include "net/base/net_util.h"
34 #include "net/base/request_priority.h"
35 #include "net/http/http_response_headers.h"
41 // Converts |time| from a remote to local TimeTicks, overwriting the original
43 void RemoteToLocalTimeTicks(
44 const InterProcessTimeTicksConverter
& converter
,
45 base::TimeTicks
* time
) {
46 RemoteTimeTicks remote_time
= RemoteTimeTicks::FromTimeTicks(*time
);
47 *time
= converter
.ToLocalTimeTicks(remote_time
).ToTimeTicks();
50 void CrashOnMapFailure() {
52 DWORD last_err
= GetLastError();
53 base::debug::Alias(&last_err
);
58 // Each resource request is assigned an ID scoped to this process.
60 // NOTE: The resource_dispatcher_host also needs probably unique
61 // request_ids, so they count down from -2 (-1 is a special we're
62 // screwed value), while the renderer process counts up.
63 static int next_request_id
= 0;
64 return next_request_id
++;
69 ResourceDispatcher::ResourceDispatcher(
71 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_task_runner
)
72 : message_sender_(sender
),
74 io_timestamp_(base::TimeTicks()),
75 main_thread_task_runner_(main_thread_task_runner
),
79 ResourceDispatcher::~ResourceDispatcher() {
82 bool ResourceDispatcher::OnMessageReceived(const IPC::Message
& message
) {
83 if (!IsResourceDispatcherMessage(message
)) {
89 base::PickleIterator
iter(message
);
90 if (!iter
.ReadInt(&request_id
)) {
91 NOTREACHED() << "malformed resource message";
95 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
97 // Release resources in the message if it is a data message.
98 ReleaseResourcesInDataMessage(message
);
102 if (request_info
->is_deferred
) {
103 request_info
->deferred_message_queue
.push_back(new IPC::Message(message
));
106 // Make sure any deferred messages are dispatched before we dispatch more.
107 if (!request_info
->deferred_message_queue
.empty()) {
108 FlushDeferredMessages(request_id
);
109 // The request could have been deferred now. If yes then the current
110 // message has to be queued up. The request_info instance should remain
111 // valid here as there are pending messages for it.
112 DCHECK(pending_requests_
.find(request_id
) != pending_requests_
.end());
113 if (request_info
->is_deferred
) {
114 request_info
->deferred_message_queue
.push_back(new IPC::Message(message
));
119 DispatchMessage(message
);
123 ResourceDispatcher::PendingRequestInfo
*
124 ResourceDispatcher::GetPendingRequestInfo(int request_id
) {
125 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
126 if (it
== pending_requests_
.end()) {
127 // This might happen for kill()ed requests on the webkit end.
130 return &(it
->second
);
133 void ResourceDispatcher::OnUploadProgress(int request_id
, int64 position
,
135 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
139 request_info
->peer
->OnUploadProgress(position
, size
);
141 // Acknowledge receipt
142 message_sender_
->Send(new ResourceHostMsg_UploadProgress_ACK(request_id
));
145 void ResourceDispatcher::OnReceivedResponse(
146 int request_id
, const ResourceResponseHead
& response_head
) {
147 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedResponse");
148 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
151 request_info
->response_start
= ConsumeIOTimestamp();
154 RequestPeer
* new_peer
=
155 delegate_
->OnReceivedResponse(
156 request_info
->peer
, response_head
.mime_type
, request_info
->url
);
158 request_info
->peer
= new_peer
;
161 ResourceResponseInfo renderer_response_info
;
162 ToResourceResponseInfo(*request_info
, response_head
, &renderer_response_info
);
163 request_info
->site_isolation_metadata
=
164 SiteIsolationPolicy::OnReceivedResponse(request_info
->frame_origin
,
165 request_info
->response_url
,
166 request_info
->resource_type
,
167 request_info
->origin_pid
,
168 renderer_response_info
);
169 request_info
->peer
->OnReceivedResponse(renderer_response_info
);
172 void ResourceDispatcher::OnReceivedCachedMetadata(
173 int request_id
, const std::vector
<char>& data
) {
174 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
179 request_info
->peer
->OnReceivedCachedMetadata(&data
.front(), data
.size());
182 void ResourceDispatcher::OnSetDataBuffer(int request_id
,
183 base::SharedMemoryHandle shm_handle
,
185 base::ProcessId renderer_pid
) {
186 TRACE_EVENT0("loader", "ResourceDispatcher::OnSetDataBuffer");
187 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
191 bool shm_valid
= base::SharedMemory::IsHandleValid(shm_handle
);
192 CHECK((shm_valid
&& shm_size
> 0) || (!shm_valid
&& !shm_size
));
194 request_info
->buffer
.reset(
195 new base::SharedMemory(shm_handle
, true)); // read only
196 request_info
->received_data_factory
=
197 make_scoped_refptr(new SharedMemoryReceivedDataFactory(
198 message_sender_
, request_id
, request_info
->buffer
));
200 bool ok
= request_info
->buffer
->Map(shm_size
);
202 // Added to help debug crbug/160401.
203 base::ProcessId renderer_pid_copy
= renderer_pid
;
204 base::debug::Alias(&renderer_pid_copy
);
206 base::SharedMemoryHandle shm_handle_copy
= shm_handle
;
207 base::debug::Alias(&shm_handle_copy
);
213 request_info
->buffer_size
= shm_size
;
216 void ResourceDispatcher::OnReceivedData(int request_id
,
219 int encoded_data_length
) {
220 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedData");
221 DCHECK_GT(data_length
, 0);
222 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
223 bool send_ack
= true;
224 if (request_info
&& data_length
> 0) {
225 CHECK(base::SharedMemory::IsHandleValid(request_info
->buffer
->handle()));
226 CHECK_GE(request_info
->buffer_size
, data_offset
+ data_length
);
228 // Ensure that the SHM buffer remains valid for the duration of this scope.
229 // It is possible for Cancel() to be called before we exit this scope.
230 // SharedMemoryReceivedDataFactory stores the SHM buffer inside it.
231 scoped_refptr
<SharedMemoryReceivedDataFactory
> factory(
232 request_info
->received_data_factory
);
234 base::TimeTicks time_start
= base::TimeTicks::Now();
236 const char* data_start
= static_cast<char*>(request_info
->buffer
->memory());
238 CHECK(data_start
+ data_offset
);
239 const char* data_ptr
= data_start
+ data_offset
;
241 // Check whether this response data is compliant with our cross-site
242 // document blocking policy. We only do this for the first packet.
243 std::string alternative_data
;
244 if (request_info
->site_isolation_metadata
.get()) {
245 request_info
->blocked_response
= SiteIsolationPolicy::ShouldBlockResponse(
246 request_info
->site_isolation_metadata
, data_ptr
, data_length
,
248 request_info
->site_isolation_metadata
.reset();
251 // When the response is blocked we may have any alternative data to
252 // send to the renderer.
253 // When |alternative_data| is zero-sized, we do not call peer's callback.
254 if (!request_info
->blocked_response
|| !alternative_data
.empty()) {
255 if (request_info
->threaded_data_provider
) {
256 // TODO(yhirano): Use |alternative_data| when it is not null.
257 // A threaded data provider will take care of its own ACKing, as the
258 // data may be processed later on another thread.
260 request_info
->threaded_data_provider
->OnReceivedDataOnForegroundThread(
261 data_ptr
, data_length
, encoded_data_length
);
263 scoped_ptr
<RequestPeer::ReceivedData
> data
;
264 if (!alternative_data
.empty()) {
265 data
= make_scoped_ptr(new FixedReceivedData(
266 alternative_data
.data(), alternative_data
.size(),
267 alternative_data
.size()));
269 data
= factory
->Create(data_offset
, data_length
, encoded_data_length
);
270 // |data| takes care of ACKing.
273 request_info
->peer
->OnReceivedData(data
.Pass());
277 UMA_HISTOGRAM_TIMES("ResourceDispatcher.OnReceivedDataTime",
278 base::TimeTicks::Now() - time_start
);
281 // Acknowledge the reception of this data.
283 message_sender_
->Send(new ResourceHostMsg_DataReceived_ACK(request_id
));
286 void ResourceDispatcher::OnDownloadedData(int request_id
,
288 int encoded_data_length
) {
289 // Acknowledge the reception of this message.
290 message_sender_
->Send(new ResourceHostMsg_DataDownloaded_ACK(request_id
));
292 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
296 request_info
->peer
->OnDownloadedData(data_len
, encoded_data_length
);
299 void ResourceDispatcher::OnReceivedRedirect(
301 const net::RedirectInfo
& redirect_info
,
302 const ResourceResponseHead
& response_head
) {
303 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedRedirect");
304 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
307 request_info
->response_start
= ConsumeIOTimestamp();
309 ResourceResponseInfo renderer_response_info
;
310 ToResourceResponseInfo(*request_info
, response_head
, &renderer_response_info
);
311 if (request_info
->peer
->OnReceivedRedirect(redirect_info
,
312 renderer_response_info
)) {
313 // Double-check if the request is still around. The call above could
314 // potentially remove it.
315 request_info
= GetPendingRequestInfo(request_id
);
318 // We update the response_url here so that we can send it to
319 // SiteIsolationPolicy later when OnReceivedResponse is called.
320 request_info
->response_url
= redirect_info
.new_url
;
321 request_info
->pending_redirect_message
.reset(
322 new ResourceHostMsg_FollowRedirect(request_id
));
323 if (!request_info
->is_deferred
) {
324 FollowPendingRedirect(request_id
, *request_info
);
331 void ResourceDispatcher::FollowPendingRedirect(
333 PendingRequestInfo
& request_info
) {
334 IPC::Message
* msg
= request_info
.pending_redirect_message
.release();
336 message_sender_
->Send(msg
);
339 void ResourceDispatcher::OnRequestComplete(
341 const ResourceMsg_RequestCompleteData
& request_complete_data
) {
342 TRACE_EVENT0("loader", "ResourceDispatcher::OnRequestComplete");
344 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
347 request_info
->completion_time
= ConsumeIOTimestamp();
348 request_info
->buffer
.reset();
349 if (request_info
->received_data_factory
)
350 request_info
->received_data_factory
->Stop();
351 request_info
->received_data_factory
= nullptr;
352 request_info
->buffer_size
= 0;
354 RequestPeer
* peer
= request_info
->peer
;
357 RequestPeer
* new_peer
=
358 delegate_
->OnRequestComplete(
359 request_info
->peer
, request_info
->resource_type
,
360 request_complete_data
.error_code
);
362 request_info
->peer
= new_peer
;
365 base::TimeTicks renderer_completion_time
= ToRendererCompletionTime(
366 *request_info
, request_complete_data
.completion_time
);
368 // If we have a threaded data provider, this message needs to bounce off the
369 // background thread before it's returned to this thread and handled,
370 // to make sure it's processed after all incoming data.
371 if (request_info
->threaded_data_provider
) {
372 request_info
->threaded_data_provider
->OnRequestCompleteForegroundThread(
373 weak_factory_
.GetWeakPtr(), request_complete_data
,
374 renderer_completion_time
);
378 // The request ID will be removed from our pending list in the destructor.
379 // Normally, dispatching this message causes the reference-counted request to
381 peer
->OnCompletedRequest(request_complete_data
.error_code
,
382 request_complete_data
.was_ignored_by_handler
,
383 request_complete_data
.exists_in_cache
,
384 request_complete_data
.security_info
,
385 renderer_completion_time
,
386 request_complete_data
.encoded_data_length
);
389 void ResourceDispatcher::CompletedRequestAfterBackgroundThreadFlush(
391 const ResourceMsg_RequestCompleteData
& request_complete_data
,
392 const base::TimeTicks
& renderer_completion_time
) {
393 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
397 RequestPeer
* peer
= request_info
->peer
;
398 peer
->OnCompletedRequest(request_complete_data
.error_code
,
399 request_complete_data
.was_ignored_by_handler
,
400 request_complete_data
.exists_in_cache
,
401 request_complete_data
.security_info
,
402 renderer_completion_time
,
403 request_complete_data
.encoded_data_length
);
406 bool ResourceDispatcher::RemovePendingRequest(int request_id
) {
407 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
408 if (it
== pending_requests_
.end())
411 PendingRequestInfo
& request_info
= it
->second
;
413 bool release_downloaded_file
= request_info
.download_to_file
;
415 ReleaseResourcesInMessageQueue(&request_info
.deferred_message_queue
);
416 pending_requests_
.erase(it
);
418 if (release_downloaded_file
) {
419 message_sender_
->Send(
420 new ResourceHostMsg_ReleaseDownloadedFile(request_id
));
426 void ResourceDispatcher::Cancel(int request_id
) {
427 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
428 if (it
== pending_requests_
.end()) {
429 DVLOG(1) << "unknown request";
433 // Cancel the request, and clean it up so the bridge will receive no more
435 message_sender_
->Send(new ResourceHostMsg_CancelRequest(request_id
));
436 RemovePendingRequest(request_id
);
439 void ResourceDispatcher::SetDefersLoading(int request_id
, bool value
) {
440 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
441 if (it
== pending_requests_
.end()) {
442 DLOG(ERROR
) << "unknown request";
445 PendingRequestInfo
& request_info
= it
->second
;
447 request_info
.is_deferred
= value
;
448 } else if (request_info
.is_deferred
) {
449 request_info
.is_deferred
= false;
451 FollowPendingRedirect(request_id
, request_info
);
453 main_thread_task_runner_
->PostTask(
454 FROM_HERE
, base::Bind(&ResourceDispatcher::FlushDeferredMessages
,
455 weak_factory_
.GetWeakPtr(), request_id
));
459 void ResourceDispatcher::DidChangePriority(int request_id
,
460 net::RequestPriority new_priority
,
461 int intra_priority_value
) {
462 DCHECK(ContainsKey(pending_requests_
, request_id
));
463 message_sender_
->Send(new ResourceHostMsg_DidChangePriority(
464 request_id
, new_priority
, intra_priority_value
));
467 bool ResourceDispatcher::AttachThreadedDataReceiver(
468 int request_id
, blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
469 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
470 DCHECK(request_info
);
472 if (request_info
->buffer
!= NULL
) {
473 DCHECK(!request_info
->threaded_data_provider
);
474 request_info
->threaded_data_provider
= new ThreadedDataProvider(
475 request_id
, threaded_data_receiver
, request_info
->buffer
,
476 request_info
->buffer_size
, main_thread_task_runner_
);
483 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo()
485 threaded_data_provider(NULL
),
486 resource_type(RESOURCE_TYPE_SUB_RESOURCE
),
488 download_to_file(false),
489 blocked_response(false),
493 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
495 ResourceType resource_type
,
497 const GURL
& frame_origin
,
498 const GURL
& request_url
,
499 bool download_to_file
)
501 threaded_data_provider(NULL
),
502 resource_type(resource_type
),
503 origin_pid(origin_pid
),
506 frame_origin(frame_origin
),
507 response_url(request_url
),
508 download_to_file(download_to_file
),
509 request_start(base::TimeTicks::Now()),
510 blocked_response(false) {}
512 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
513 if (threaded_data_provider
)
514 threaded_data_provider
->Stop();
517 void ResourceDispatcher::DispatchMessage(const IPC::Message
& message
) {
518 IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher
, message
)
519 IPC_MESSAGE_HANDLER(ResourceMsg_UploadProgress
, OnUploadProgress
)
520 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedResponse
, OnReceivedResponse
)
521 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedCachedMetadata
,
522 OnReceivedCachedMetadata
)
523 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect
, OnReceivedRedirect
)
524 IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer
, OnSetDataBuffer
)
525 IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived
, OnReceivedData
)
526 IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded
, OnDownloadedData
)
527 IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete
, OnRequestComplete
)
528 IPC_END_MESSAGE_MAP()
531 void ResourceDispatcher::FlushDeferredMessages(int request_id
) {
532 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
533 if (it
== pending_requests_
.end()) // The request could have become invalid.
535 PendingRequestInfo
& request_info
= it
->second
;
536 if (request_info
.is_deferred
)
538 // Because message handlers could result in request_info being destroyed,
539 // we need to work with a stack reference to the deferred queue.
541 q
.swap(request_info
.deferred_message_queue
);
543 IPC::Message
* m
= q
.front();
547 // If this request is deferred in the context of the above message, then
548 // we should honor the same and stop dispatching further messages.
549 // We need to find the request again in the list as it may have completed
550 // by now and the request_info instance above may be invalid.
551 PendingRequestList::iterator index
= pending_requests_
.find(request_id
);
552 if (index
!= pending_requests_
.end()) {
553 PendingRequestInfo
& pending_request
= index
->second
;
554 if (pending_request
.is_deferred
) {
555 pending_request
.deferred_message_queue
.swap(q
);
562 void ResourceDispatcher::StartSync(const RequestInfo
& request_info
,
563 ResourceRequestBody
* request_body
,
564 SyncLoadResponse
* response
) {
565 scoped_ptr
<ResourceHostMsg_Request
> request
=
566 CreateRequest(request_info
, request_body
, NULL
);
568 SyncLoadResult result
;
569 IPC::SyncMessage
* msg
= new ResourceHostMsg_SyncLoad(
570 request_info
.routing_id
, MakeRequestID(), *request
, &result
);
572 // NOTE: This may pump events (see RenderThread::Send).
573 if (!message_sender_
->Send(msg
)) {
574 response
->error_code
= net::ERR_FAILED
;
578 response
->error_code
= result
.error_code
;
579 response
->url
= result
.final_url
;
580 response
->headers
= result
.headers
;
581 response
->mime_type
= result
.mime_type
;
582 response
->charset
= result
.charset
;
583 response
->request_time
= result
.request_time
;
584 response
->response_time
= result
.response_time
;
585 response
->encoded_data_length
= result
.encoded_data_length
;
586 response
->load_timing
= result
.load_timing
;
587 response
->devtools_info
= result
.devtools_info
;
588 response
->data
.swap(result
.data
);
589 response
->download_file_path
= result
.download_file_path
;
592 int ResourceDispatcher::StartAsync(const RequestInfo
& request_info
,
593 ResourceRequestBody
* request_body
,
596 scoped_ptr
<ResourceHostMsg_Request
> request
=
597 CreateRequest(request_info
, request_body
, &frame_origin
);
599 // Compute a unique request_id for this renderer process.
600 int request_id
= MakeRequestID();
601 pending_requests_
[request_id
] =
602 PendingRequestInfo(peer
,
603 request
->resource_type
,
607 request_info
.download_to_file
);
609 message_sender_
->Send(new ResourceHostMsg_RequestResource(
610 request_info
.routing_id
, request_id
, *request
));
615 void ResourceDispatcher::ToResourceResponseInfo(
616 const PendingRequestInfo
& request_info
,
617 const ResourceResponseHead
& browser_info
,
618 ResourceResponseInfo
* renderer_info
) const {
619 *renderer_info
= browser_info
;
620 if (request_info
.request_start
.is_null() ||
621 request_info
.response_start
.is_null() ||
622 browser_info
.request_start
.is_null() ||
623 browser_info
.response_start
.is_null() ||
624 browser_info
.load_timing
.request_start
.is_null()) {
627 InterProcessTimeTicksConverter
converter(
628 LocalTimeTicks::FromTimeTicks(request_info
.request_start
),
629 LocalTimeTicks::FromTimeTicks(request_info
.response_start
),
630 RemoteTimeTicks::FromTimeTicks(browser_info
.request_start
),
631 RemoteTimeTicks::FromTimeTicks(browser_info
.response_start
));
633 net::LoadTimingInfo
* load_timing
= &renderer_info
->load_timing
;
634 RemoteToLocalTimeTicks(converter
, &load_timing
->request_start
);
635 RemoteToLocalTimeTicks(converter
, &load_timing
->proxy_resolve_start
);
636 RemoteToLocalTimeTicks(converter
, &load_timing
->proxy_resolve_end
);
637 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.dns_start
);
638 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.dns_end
);
639 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.connect_start
);
640 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.connect_end
);
641 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.ssl_start
);
642 RemoteToLocalTimeTicks(converter
, &load_timing
->connect_timing
.ssl_end
);
643 RemoteToLocalTimeTicks(converter
, &load_timing
->send_start
);
644 RemoteToLocalTimeTicks(converter
, &load_timing
->send_end
);
645 RemoteToLocalTimeTicks(converter
, &load_timing
->receive_headers_end
);
646 RemoteToLocalTimeTicks(converter
, &renderer_info
->service_worker_start_time
);
647 RemoteToLocalTimeTicks(converter
, &renderer_info
->service_worker_ready_time
);
649 // Collect UMA on the inter-process skew.
650 bool is_skew_additive
= false;
651 if (converter
.IsSkewAdditiveForMetrics()) {
652 is_skew_additive
= true;
653 base::TimeDelta skew
= converter
.GetSkewForMetrics();
654 if (skew
>= base::TimeDelta()) {
656 "InterProcessTimeTicks.BrowserAhead_BrowserToRenderer", skew
);
659 "InterProcessTimeTicks.BrowserBehind_BrowserToRenderer", -skew
);
662 UMA_HISTOGRAM_BOOLEAN(
663 "InterProcessTimeTicks.IsSkewAdditive_BrowserToRenderer",
667 base::TimeTicks
ResourceDispatcher::ToRendererCompletionTime(
668 const PendingRequestInfo
& request_info
,
669 const base::TimeTicks
& browser_completion_time
) const {
670 if (request_info
.completion_time
.is_null()) {
671 return browser_completion_time
;
674 // TODO(simonjam): The optimal lower bound should be the most recent value of
675 // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that?
676 // Until then, |response_start| is used as it is the most recent value
677 // returned for this request.
678 int64 result
= std::max(browser_completion_time
.ToInternalValue(),
679 request_info
.response_start
.ToInternalValue());
680 result
= std::min(result
, request_info
.completion_time
.ToInternalValue());
681 return base::TimeTicks::FromInternalValue(result
);
684 base::TimeTicks
ResourceDispatcher::ConsumeIOTimestamp() {
685 if (io_timestamp_
== base::TimeTicks())
686 return base::TimeTicks::Now();
687 base::TimeTicks result
= io_timestamp_
;
688 io_timestamp_
= base::TimeTicks();
693 bool ResourceDispatcher::IsResourceDispatcherMessage(
694 const IPC::Message
& message
) {
695 switch (message
.type()) {
696 case ResourceMsg_UploadProgress::ID
:
697 case ResourceMsg_ReceivedResponse::ID
:
698 case ResourceMsg_ReceivedCachedMetadata::ID
:
699 case ResourceMsg_ReceivedRedirect::ID
:
700 case ResourceMsg_SetDataBuffer::ID
:
701 case ResourceMsg_DataReceived::ID
:
702 case ResourceMsg_DataDownloaded::ID
:
703 case ResourceMsg_RequestComplete::ID
:
714 void ResourceDispatcher::ReleaseResourcesInDataMessage(
715 const IPC::Message
& message
) {
716 base::PickleIterator
iter(message
);
718 if (!iter
.ReadInt(&request_id
)) {
719 NOTREACHED() << "malformed resource message";
723 // If the message contains a shared memory handle, we should close the handle
724 // or there will be a memory leak.
725 if (message
.type() == ResourceMsg_SetDataBuffer::ID
) {
726 base::SharedMemoryHandle shm_handle
;
727 if (IPC::ParamTraits
<base::SharedMemoryHandle
>::Read(&message
,
730 if (base::SharedMemory::IsHandleValid(shm_handle
))
731 base::SharedMemory::CloseHandle(shm_handle
);
737 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue
* queue
) {
738 while (!queue
->empty()) {
739 IPC::Message
* message
= queue
->front();
740 ReleaseResourcesInDataMessage(*message
);
746 scoped_ptr
<ResourceHostMsg_Request
> ResourceDispatcher::CreateRequest(
747 const RequestInfo
& request_info
,
748 ResourceRequestBody
* request_body
,
749 GURL
* frame_origin
) {
750 scoped_ptr
<ResourceHostMsg_Request
> request(new ResourceHostMsg_Request
);
751 request
->method
= request_info
.method
;
752 request
->url
= request_info
.url
;
753 request
->first_party_for_cookies
= request_info
.first_party_for_cookies
;
754 request
->referrer
= request_info
.referrer
.url
;
755 request
->referrer_policy
= request_info
.referrer
.policy
;
756 request
->headers
= request_info
.headers
;
757 request
->load_flags
= request_info
.load_flags
;
758 request
->origin_pid
= request_info
.requestor_pid
;
759 request
->resource_type
= request_info
.request_type
;
760 request
->priority
= request_info
.priority
;
761 request
->request_context
= request_info
.request_context
;
762 request
->appcache_host_id
= request_info
.appcache_host_id
;
763 request
->download_to_file
= request_info
.download_to_file
;
764 request
->has_user_gesture
= request_info
.has_user_gesture
;
765 request
->skip_service_worker
= request_info
.skip_service_worker
;
766 request
->should_reset_appcache
= request_info
.should_reset_appcache
;
767 request
->fetch_request_mode
= request_info
.fetch_request_mode
;
768 request
->fetch_credentials_mode
= request_info
.fetch_credentials_mode
;
769 request
->fetch_request_context_type
= request_info
.fetch_request_context_type
;
770 request
->fetch_frame_type
= request_info
.fetch_frame_type
;
771 request
->enable_load_timing
= request_info
.enable_load_timing
;
772 request
->enable_upload_progress
= request_info
.enable_upload_progress
;
773 request
->do_not_prompt_for_login
= request_info
.do_not_prompt_for_login
;
775 if ((request_info
.referrer
.policy
== blink::WebReferrerPolicyDefault
||
776 request_info
.referrer
.policy
==
777 blink::WebReferrerPolicyNoReferrerWhenDowngrade
) &&
778 request_info
.referrer
.url
.SchemeIsCryptographic() &&
779 !request_info
.url
.SchemeIsCryptographic()) {
780 LOG(FATAL
) << "Trying to send secure referrer for insecure request "
781 << "without an appropriate referrer policy.\n"
782 << "URL = " << request_info
.url
<< "\n"
783 << "Referrer = " << request_info
.referrer
.url
;
786 const RequestExtraData kEmptyData
;
787 const RequestExtraData
* extra_data
;
788 if (request_info
.extra_data
)
789 extra_data
= static_cast<RequestExtraData
*>(request_info
.extra_data
);
791 extra_data
= &kEmptyData
;
792 request
->visiblity_state
= extra_data
->visibility_state();
793 request
->render_frame_id
= extra_data
->render_frame_id();
794 request
->is_main_frame
= extra_data
->is_main_frame();
795 request
->parent_is_main_frame
= extra_data
->parent_is_main_frame();
796 request
->parent_render_frame_id
= extra_data
->parent_render_frame_id();
797 request
->allow_download
= extra_data
->allow_download();
798 request
->transition_type
= extra_data
->transition_type();
799 request
->should_replace_current_entry
=
800 extra_data
->should_replace_current_entry();
801 request
->transferred_request_child_id
=
802 extra_data
->transferred_request_child_id();
803 request
->transferred_request_request_id
=
804 extra_data
->transferred_request_request_id();
805 request
->service_worker_provider_id
=
806 extra_data
->service_worker_provider_id();
807 request
->request_body
= request_body
;
809 *frame_origin
= extra_data
->frame_origin();
810 return request
.Pass();
813 } // namespace content