Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / resource_dispatcher.cc
blobcf56a77c8a0556d01b64afb1d40e1bbba3732faa
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/site_isolation_policy.h"
22 #include "content/child/sync_load_response.h"
23 #include "content/child/threaded_data_provider.h"
24 #include "content/common/inter_process_time_ticks_converter.h"
25 #include "content/common/resource_messages.h"
26 #include "content/public/child/request_peer.h"
27 #include "content/public/child/resource_dispatcher_delegate.h"
28 #include "content/public/common/resource_response.h"
29 #include "content/public/common/resource_type.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/net_util.h"
32 #include "net/base/request_priority.h"
33 #include "net/http/http_response_headers.h"
35 namespace content {
37 namespace {
39 // Converts |time| from a remote to local TimeTicks, overwriting the original
40 // value.
41 void RemoteToLocalTimeTicks(
42 const InterProcessTimeTicksConverter& converter,
43 base::TimeTicks* time) {
44 RemoteTimeTicks remote_time = RemoteTimeTicks::FromTimeTicks(*time);
45 *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
48 void CrashOnMapFailure() {
49 #if defined(OS_WIN)
50 DWORD last_err = GetLastError();
51 base::debug::Alias(&last_err);
52 #endif
53 CHECK(false);
56 // Each resource request is assigned an ID scoped to this process.
57 int MakeRequestID() {
58 // NOTE: The resource_dispatcher_host also needs probably unique
59 // request_ids, so they count down from -2 (-1 is a special we're
60 // screwed value), while the renderer process counts up.
61 static int next_request_id = 0;
62 return next_request_id++;
65 } // namespace
67 ResourceDispatcher::ResourceDispatcher(
68 IPC::Sender* sender,
69 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
70 : message_sender_(sender),
71 delegate_(NULL),
72 io_timestamp_(base::TimeTicks()),
73 main_thread_task_runner_(main_thread_task_runner),
74 weak_factory_(this) {
77 ResourceDispatcher::~ResourceDispatcher() {
80 bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
81 if (!IsResourceDispatcherMessage(message)) {
82 return false;
85 int request_id;
87 PickleIterator iter(message);
88 if (!iter.ReadInt(&request_id)) {
89 NOTREACHED() << "malformed resource message";
90 return true;
93 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
94 if (!request_info) {
95 // Release resources in the message if it is a data message.
96 ReleaseResourcesInDataMessage(message);
97 return true;
100 if (request_info->is_deferred) {
101 request_info->deferred_message_queue.push_back(new IPC::Message(message));
102 return true;
104 // Make sure any deferred messages are dispatched before we dispatch more.
105 if (!request_info->deferred_message_queue.empty()) {
106 FlushDeferredMessages(request_id);
107 // The request could have been deferred now. If yes then the current
108 // message has to be queued up. The request_info instance should remain
109 // valid here as there are pending messages for it.
110 DCHECK(pending_requests_.find(request_id) != pending_requests_.end());
111 if (request_info->is_deferred) {
112 request_info->deferred_message_queue.push_back(new IPC::Message(message));
113 return true;
117 DispatchMessage(message);
118 return true;
121 ResourceDispatcher::PendingRequestInfo*
122 ResourceDispatcher::GetPendingRequestInfo(int request_id) {
123 PendingRequestList::iterator it = pending_requests_.find(request_id);
124 if (it == pending_requests_.end()) {
125 // This might happen for kill()ed requests on the webkit end.
126 return NULL;
128 return &(it->second);
131 void ResourceDispatcher::OnUploadProgress(int request_id, int64 position,
132 int64 size) {
133 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
134 if (!request_info)
135 return;
137 request_info->peer->OnUploadProgress(position, size);
139 // Acknowledge receipt
140 message_sender_->Send(new ResourceHostMsg_UploadProgress_ACK(request_id));
143 void ResourceDispatcher::OnReceivedResponse(
144 int request_id, const ResourceResponseHead& response_head) {
145 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedResponse");
146 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
147 if (!request_info)
148 return;
149 request_info->response_start = ConsumeIOTimestamp();
151 if (delegate_) {
152 RequestPeer* new_peer =
153 delegate_->OnReceivedResponse(
154 request_info->peer, response_head.mime_type, request_info->url);
155 if (new_peer)
156 request_info->peer = new_peer;
159 ResourceResponseInfo renderer_response_info;
160 ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
161 request_info->site_isolation_metadata =
162 SiteIsolationPolicy::OnReceivedResponse(request_info->frame_origin,
163 request_info->response_url,
164 request_info->resource_type,
165 request_info->origin_pid,
166 renderer_response_info);
167 request_info->peer->OnReceivedResponse(renderer_response_info);
170 void ResourceDispatcher::OnReceivedCachedMetadata(
171 int request_id, const std::vector<char>& data) {
172 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
173 if (!request_info)
174 return;
176 if (data.size())
177 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
180 void ResourceDispatcher::OnSetDataBuffer(int request_id,
181 base::SharedMemoryHandle shm_handle,
182 int shm_size,
183 base::ProcessId renderer_pid) {
184 TRACE_EVENT0("loader", "ResourceDispatcher::OnSetDataBuffer");
185 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
186 if (!request_info)
187 return;
189 bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle);
190 CHECK((shm_valid && shm_size > 0) || (!shm_valid && !shm_size));
192 request_info->buffer.reset(
193 new base::SharedMemory(shm_handle, true)); // read only
195 bool ok = request_info->buffer->Map(shm_size);
196 if (!ok) {
197 // Added to help debug crbug/160401.
198 base::ProcessId renderer_pid_copy = renderer_pid;
199 base::debug::Alias(&renderer_pid_copy);
201 base::SharedMemoryHandle shm_handle_copy = shm_handle;
202 base::debug::Alias(&shm_handle_copy);
204 CrashOnMapFailure();
205 return;
208 request_info->buffer_size = shm_size;
211 void ResourceDispatcher::OnReceivedData(int request_id,
212 int data_offset,
213 int data_length,
214 int encoded_data_length) {
215 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedData");
216 DCHECK_GT(data_length, 0);
217 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
218 bool send_ack = true;
219 if (request_info && data_length > 0) {
220 CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle()));
221 CHECK_GE(request_info->buffer_size, data_offset + data_length);
223 // Ensure that the SHM buffer remains valid for the duration of this scope.
224 // It is possible for Cancel() to be called before we exit this scope.
225 linked_ptr<base::SharedMemory> retain_buffer(request_info->buffer);
227 base::TimeTicks time_start = base::TimeTicks::Now();
229 const char* data_start = static_cast<char*>(request_info->buffer->memory());
230 CHECK(data_start);
231 CHECK(data_start + data_offset);
232 const char* data_ptr = data_start + data_offset;
234 // Check whether this response data is compliant with our cross-site
235 // document blocking policy. We only do this for the first packet.
236 std::string alternative_data;
237 if (request_info->site_isolation_metadata.get()) {
238 request_info->blocked_response =
239 SiteIsolationPolicy::ShouldBlockResponse(
240 request_info->site_isolation_metadata, data_ptr, data_length,
241 &alternative_data);
242 request_info->site_isolation_metadata.reset();
244 // When the response is blocked we may have any alternative data to
245 // send to the renderer. When |alternative_data| is zero-sized, we do not
246 // call peer's callback.
247 if (request_info->blocked_response && !alternative_data.empty()) {
248 data_ptr = alternative_data.data();
249 data_length = alternative_data.size();
250 encoded_data_length = alternative_data.size();
254 if (!request_info->blocked_response || !alternative_data.empty()) {
255 if (request_info->threaded_data_provider) {
256 request_info->threaded_data_provider->OnReceivedDataOnForegroundThread(
257 data_ptr, data_length, encoded_data_length);
258 // A threaded data provider will take care of its own ACKing, as the
259 // data may be processed later on another thread.
260 send_ack = false;
261 } else {
262 request_info->peer->OnReceivedData(
263 data_ptr, data_length, encoded_data_length);
267 UMA_HISTOGRAM_TIMES("ResourceDispatcher.OnReceivedDataTime",
268 base::TimeTicks::Now() - time_start);
271 // Acknowledge the reception of this data.
272 if (send_ack)
273 message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id));
276 void ResourceDispatcher::OnDownloadedData(int request_id,
277 int data_len,
278 int encoded_data_length) {
279 // Acknowledge the reception of this message.
280 message_sender_->Send(new ResourceHostMsg_DataDownloaded_ACK(request_id));
282 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
283 if (!request_info)
284 return;
286 request_info->peer->OnDownloadedData(data_len, encoded_data_length);
289 void ResourceDispatcher::OnReceivedRedirect(
290 int request_id,
291 const net::RedirectInfo& redirect_info,
292 const ResourceResponseHead& response_head) {
293 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedRedirect");
294 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
295 if (!request_info)
296 return;
297 request_info->response_start = ConsumeIOTimestamp();
299 ResourceResponseInfo renderer_response_info;
300 ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
301 if (request_info->peer->OnReceivedRedirect(redirect_info,
302 renderer_response_info)) {
303 // Double-check if the request is still around. The call above could
304 // potentially remove it.
305 request_info = GetPendingRequestInfo(request_id);
306 if (!request_info)
307 return;
308 // We update the response_url here so that we can send it to
309 // SiteIsolationPolicy later when OnReceivedResponse is called.
310 request_info->response_url = redirect_info.new_url;
311 request_info->pending_redirect_message.reset(
312 new ResourceHostMsg_FollowRedirect(request_id));
313 if (!request_info->is_deferred) {
314 FollowPendingRedirect(request_id, *request_info);
316 } else {
317 Cancel(request_id);
321 void ResourceDispatcher::FollowPendingRedirect(
322 int request_id,
323 PendingRequestInfo& request_info) {
324 IPC::Message* msg = request_info.pending_redirect_message.release();
325 if (msg)
326 message_sender_->Send(msg);
329 void ResourceDispatcher::OnRequestComplete(
330 int request_id,
331 const ResourceMsg_RequestCompleteData& request_complete_data) {
332 TRACE_EVENT0("loader", "ResourceDispatcher::OnRequestComplete");
334 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
335 if (!request_info)
336 return;
337 request_info->completion_time = ConsumeIOTimestamp();
338 request_info->buffer.reset();
339 request_info->buffer_size = 0;
341 RequestPeer* peer = request_info->peer;
343 if (delegate_) {
344 RequestPeer* new_peer =
345 delegate_->OnRequestComplete(
346 request_info->peer, request_info->resource_type,
347 request_complete_data.error_code);
348 if (new_peer)
349 request_info->peer = new_peer;
352 base::TimeTicks renderer_completion_time = ToRendererCompletionTime(
353 *request_info, request_complete_data.completion_time);
355 // If we have a threaded data provider, this message needs to bounce off the
356 // background thread before it's returned to this thread and handled,
357 // to make sure it's processed after all incoming data.
358 if (request_info->threaded_data_provider) {
359 request_info->threaded_data_provider->OnRequestCompleteForegroundThread(
360 weak_factory_.GetWeakPtr(), request_complete_data,
361 renderer_completion_time);
362 return;
365 // The request ID will be removed from our pending list in the destructor.
366 // Normally, dispatching this message causes the reference-counted request to
367 // die immediately.
368 peer->OnCompletedRequest(request_complete_data.error_code,
369 request_complete_data.was_ignored_by_handler,
370 request_complete_data.exists_in_cache,
371 request_complete_data.security_info,
372 renderer_completion_time,
373 request_complete_data.encoded_data_length);
376 void ResourceDispatcher::CompletedRequestAfterBackgroundThreadFlush(
377 int request_id,
378 const ResourceMsg_RequestCompleteData& request_complete_data,
379 const base::TimeTicks& renderer_completion_time) {
380 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
381 if (!request_info)
382 return;
384 RequestPeer* peer = request_info->peer;
385 peer->OnCompletedRequest(request_complete_data.error_code,
386 request_complete_data.was_ignored_by_handler,
387 request_complete_data.exists_in_cache,
388 request_complete_data.security_info,
389 renderer_completion_time,
390 request_complete_data.encoded_data_length);
393 bool ResourceDispatcher::RemovePendingRequest(int request_id) {
394 PendingRequestList::iterator it = pending_requests_.find(request_id);
395 if (it == pending_requests_.end())
396 return false;
398 PendingRequestInfo& request_info = it->second;
400 bool release_downloaded_file = request_info.download_to_file;
402 ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue);
403 pending_requests_.erase(it);
405 if (release_downloaded_file) {
406 message_sender_->Send(
407 new ResourceHostMsg_ReleaseDownloadedFile(request_id));
410 return true;
413 void ResourceDispatcher::Cancel(int request_id) {
414 PendingRequestList::iterator it = pending_requests_.find(request_id);
415 if (it == pending_requests_.end()) {
416 DVLOG(1) << "unknown request";
417 return;
420 // Cancel the request, and clean it up so the bridge will receive no more
421 // messages.
422 message_sender_->Send(new ResourceHostMsg_CancelRequest(request_id));
423 RemovePendingRequest(request_id);
426 void ResourceDispatcher::SetDefersLoading(int request_id, bool value) {
427 PendingRequestList::iterator it = pending_requests_.find(request_id);
428 if (it == pending_requests_.end()) {
429 DLOG(ERROR) << "unknown request";
430 return;
432 PendingRequestInfo& request_info = it->second;
433 if (value) {
434 request_info.is_deferred = value;
435 } else if (request_info.is_deferred) {
436 request_info.is_deferred = false;
438 FollowPendingRedirect(request_id, request_info);
440 main_thread_task_runner_->PostTask(
441 FROM_HERE, base::Bind(&ResourceDispatcher::FlushDeferredMessages,
442 weak_factory_.GetWeakPtr(), request_id));
446 void ResourceDispatcher::DidChangePriority(int request_id,
447 net::RequestPriority new_priority,
448 int intra_priority_value) {
449 DCHECK(ContainsKey(pending_requests_, request_id));
450 message_sender_->Send(new ResourceHostMsg_DidChangePriority(
451 request_id, new_priority, intra_priority_value));
454 bool ResourceDispatcher::AttachThreadedDataReceiver(
455 int request_id, blink::WebThreadedDataReceiver* threaded_data_receiver) {
456 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
457 DCHECK(request_info);
459 if (request_info->buffer != NULL) {
460 DCHECK(!request_info->threaded_data_provider);
461 request_info->threaded_data_provider = new ThreadedDataProvider(
462 request_id, threaded_data_receiver, request_info->buffer,
463 request_info->buffer_size, main_thread_task_runner_);
464 return true;
467 return false;
470 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo()
471 : peer(NULL),
472 threaded_data_provider(NULL),
473 resource_type(RESOURCE_TYPE_SUB_RESOURCE),
474 is_deferred(false),
475 download_to_file(false),
476 blocked_response(false),
477 buffer_size(0) {
480 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
481 RequestPeer* peer,
482 ResourceType resource_type,
483 int origin_pid,
484 const GURL& frame_origin,
485 const GURL& request_url,
486 bool download_to_file)
487 : peer(peer),
488 threaded_data_provider(NULL),
489 resource_type(resource_type),
490 origin_pid(origin_pid),
491 is_deferred(false),
492 url(request_url),
493 frame_origin(frame_origin),
494 response_url(request_url),
495 download_to_file(download_to_file),
496 request_start(base::TimeTicks::Now()),
497 blocked_response(false) {}
499 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
500 if (threaded_data_provider)
501 threaded_data_provider->Stop();
504 void ResourceDispatcher::DispatchMessage(const IPC::Message& message) {
505 IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message)
506 IPC_MESSAGE_HANDLER(ResourceMsg_UploadProgress, OnUploadProgress)
507 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedResponse, OnReceivedResponse)
508 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedCachedMetadata,
509 OnReceivedCachedMetadata)
510 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect, OnReceivedRedirect)
511 IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
512 IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived, OnReceivedData)
513 IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded, OnDownloadedData)
514 IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete, OnRequestComplete)
515 IPC_END_MESSAGE_MAP()
518 void ResourceDispatcher::FlushDeferredMessages(int request_id) {
519 PendingRequestList::iterator it = pending_requests_.find(request_id);
520 if (it == pending_requests_.end()) // The request could have become invalid.
521 return;
522 PendingRequestInfo& request_info = it->second;
523 if (request_info.is_deferred)
524 return;
525 // Because message handlers could result in request_info being destroyed,
526 // we need to work with a stack reference to the deferred queue.
527 MessageQueue q;
528 q.swap(request_info.deferred_message_queue);
529 while (!q.empty()) {
530 IPC::Message* m = q.front();
531 q.pop_front();
532 DispatchMessage(*m);
533 delete m;
534 // If this request is deferred in the context of the above message, then
535 // we should honor the same and stop dispatching further messages.
536 // We need to find the request again in the list as it may have completed
537 // by now and the request_info instance above may be invalid.
538 PendingRequestList::iterator index = pending_requests_.find(request_id);
539 if (index != pending_requests_.end()) {
540 PendingRequestInfo& pending_request = index->second;
541 if (pending_request.is_deferred) {
542 pending_request.deferred_message_queue.swap(q);
543 return;
549 void ResourceDispatcher::StartSync(const RequestInfo& request_info,
550 ResourceRequestBody* request_body,
551 SyncLoadResponse* response) {
552 scoped_ptr<ResourceHostMsg_Request> request =
553 CreateRequest(request_info, request_body, NULL);
555 SyncLoadResult result;
556 IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(
557 request_info.routing_id, MakeRequestID(), *request, &result);
559 // NOTE: This may pump events (see RenderThread::Send).
560 if (!message_sender_->Send(msg)) {
561 response->error_code = net::ERR_FAILED;
562 return;
565 response->error_code = result.error_code;
566 response->url = result.final_url;
567 response->headers = result.headers;
568 response->mime_type = result.mime_type;
569 response->charset = result.charset;
570 response->request_time = result.request_time;
571 response->response_time = result.response_time;
572 response->encoded_data_length = result.encoded_data_length;
573 response->load_timing = result.load_timing;
574 response->devtools_info = result.devtools_info;
575 response->data.swap(result.data);
576 response->download_file_path = result.download_file_path;
579 int ResourceDispatcher::StartAsync(const RequestInfo& request_info,
580 ResourceRequestBody* request_body,
581 RequestPeer* peer) {
582 GURL frame_origin;
583 scoped_ptr<ResourceHostMsg_Request> request =
584 CreateRequest(request_info, request_body, &frame_origin);
586 // Compute a unique request_id for this renderer process.
587 int request_id = MakeRequestID();
588 pending_requests_[request_id] =
589 PendingRequestInfo(peer,
590 request->resource_type,
591 request->origin_pid,
592 frame_origin,
593 request->url,
594 request_info.download_to_file);
596 message_sender_->Send(new ResourceHostMsg_RequestResource(
597 request_info.routing_id, request_id, *request));
599 return request_id;
602 void ResourceDispatcher::ToResourceResponseInfo(
603 const PendingRequestInfo& request_info,
604 const ResourceResponseHead& browser_info,
605 ResourceResponseInfo* renderer_info) const {
606 *renderer_info = browser_info;
607 if (request_info.request_start.is_null() ||
608 request_info.response_start.is_null() ||
609 browser_info.request_start.is_null() ||
610 browser_info.response_start.is_null() ||
611 browser_info.load_timing.request_start.is_null()) {
612 return;
614 InterProcessTimeTicksConverter converter(
615 LocalTimeTicks::FromTimeTicks(request_info.request_start),
616 LocalTimeTicks::FromTimeTicks(request_info.response_start),
617 RemoteTimeTicks::FromTimeTicks(browser_info.request_start),
618 RemoteTimeTicks::FromTimeTicks(browser_info.response_start));
620 net::LoadTimingInfo* load_timing = &renderer_info->load_timing;
621 RemoteToLocalTimeTicks(converter, &load_timing->request_start);
622 RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_start);
623 RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_end);
624 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_start);
625 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_end);
626 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_start);
627 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_end);
628 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_start);
629 RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_end);
630 RemoteToLocalTimeTicks(converter, &load_timing->send_start);
631 RemoteToLocalTimeTicks(converter, &load_timing->send_end);
632 RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end);
633 RemoteToLocalTimeTicks(converter,
634 &renderer_info->service_worker_fetch_start);
635 RemoteToLocalTimeTicks(converter,
636 &renderer_info->service_worker_fetch_ready);
637 RemoteToLocalTimeTicks(converter,
638 &renderer_info->service_worker_fetch_end);
640 // Collect UMA on the inter-process skew.
641 bool is_skew_additive = false;
642 if (converter.IsSkewAdditiveForMetrics()) {
643 is_skew_additive = true;
644 base::TimeDelta skew = converter.GetSkewForMetrics();
645 if (skew >= base::TimeDelta()) {
646 UMA_HISTOGRAM_TIMES(
647 "InterProcessTimeTicks.BrowserAhead_BrowserToRenderer", skew);
648 } else {
649 UMA_HISTOGRAM_TIMES(
650 "InterProcessTimeTicks.BrowserBehind_BrowserToRenderer", -skew);
653 UMA_HISTOGRAM_BOOLEAN(
654 "InterProcessTimeTicks.IsSkewAdditive_BrowserToRenderer",
655 is_skew_additive);
658 base::TimeTicks ResourceDispatcher::ToRendererCompletionTime(
659 const PendingRequestInfo& request_info,
660 const base::TimeTicks& browser_completion_time) const {
661 if (request_info.completion_time.is_null()) {
662 return browser_completion_time;
665 // TODO(simonjam): The optimal lower bound should be the most recent value of
666 // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that?
667 // Until then, |response_start| is used as it is the most recent value
668 // returned for this request.
669 int64 result = std::max(browser_completion_time.ToInternalValue(),
670 request_info.response_start.ToInternalValue());
671 result = std::min(result, request_info.completion_time.ToInternalValue());
672 return base::TimeTicks::FromInternalValue(result);
675 base::TimeTicks ResourceDispatcher::ConsumeIOTimestamp() {
676 if (io_timestamp_ == base::TimeTicks())
677 return base::TimeTicks::Now();
678 base::TimeTicks result = io_timestamp_;
679 io_timestamp_ = base::TimeTicks();
680 return result;
683 // static
684 bool ResourceDispatcher::IsResourceDispatcherMessage(
685 const IPC::Message& message) {
686 switch (message.type()) {
687 case ResourceMsg_UploadProgress::ID:
688 case ResourceMsg_ReceivedResponse::ID:
689 case ResourceMsg_ReceivedCachedMetadata::ID:
690 case ResourceMsg_ReceivedRedirect::ID:
691 case ResourceMsg_SetDataBuffer::ID:
692 case ResourceMsg_DataReceived::ID:
693 case ResourceMsg_DataDownloaded::ID:
694 case ResourceMsg_RequestComplete::ID:
695 return true;
697 default:
698 break;
701 return false;
704 // static
705 void ResourceDispatcher::ReleaseResourcesInDataMessage(
706 const IPC::Message& message) {
707 PickleIterator iter(message);
708 int request_id;
709 if (!iter.ReadInt(&request_id)) {
710 NOTREACHED() << "malformed resource message";
711 return;
714 // If the message contains a shared memory handle, we should close the handle
715 // or there will be a memory leak.
716 if (message.type() == ResourceMsg_SetDataBuffer::ID) {
717 base::SharedMemoryHandle shm_handle;
718 if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message,
719 &iter,
720 &shm_handle)) {
721 if (base::SharedMemory::IsHandleValid(shm_handle))
722 base::SharedMemory::CloseHandle(shm_handle);
727 // static
728 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
729 while (!queue->empty()) {
730 IPC::Message* message = queue->front();
731 ReleaseResourcesInDataMessage(*message);
732 queue->pop_front();
733 delete message;
737 scoped_ptr<ResourceHostMsg_Request> ResourceDispatcher::CreateRequest(
738 const RequestInfo& request_info,
739 ResourceRequestBody* request_body,
740 GURL* frame_origin) {
741 scoped_ptr<ResourceHostMsg_Request> request(new ResourceHostMsg_Request);
742 request->method = request_info.method;
743 request->url = request_info.url;
744 request->first_party_for_cookies = request_info.first_party_for_cookies;
745 request->referrer = request_info.referrer.url;
746 request->referrer_policy = request_info.referrer.policy;
747 request->headers = request_info.headers;
748 request->load_flags = request_info.load_flags;
749 request->origin_pid = request_info.requestor_pid;
750 request->resource_type = request_info.request_type;
751 request->priority = request_info.priority;
752 request->request_context = request_info.request_context;
753 request->appcache_host_id = request_info.appcache_host_id;
754 request->download_to_file = request_info.download_to_file;
755 request->has_user_gesture = request_info.has_user_gesture;
756 request->skip_service_worker = request_info.skip_service_worker;
757 request->should_reset_appcache = request_info.should_reset_appcache;
758 request->fetch_request_mode = request_info.fetch_request_mode;
759 request->fetch_credentials_mode = request_info.fetch_credentials_mode;
760 request->fetch_request_context_type = request_info.fetch_request_context_type;
761 request->fetch_frame_type = request_info.fetch_frame_type;
762 request->enable_load_timing = request_info.enable_load_timing;
763 request->enable_upload_progress = request_info.enable_upload_progress;
764 request->do_not_prompt_for_login = request_info.do_not_prompt_for_login;
766 if ((request_info.referrer.policy == blink::WebReferrerPolicyDefault ||
767 request_info.referrer.policy ==
768 blink::WebReferrerPolicyNoReferrerWhenDowngrade) &&
769 request_info.referrer.url.SchemeIsSecure() &&
770 !request_info.url.SchemeIsSecure()) {
771 LOG(FATAL) << "Trying to send secure referrer for insecure request "
772 << "without an appropriate referrer policy.\n"
773 << "URL = " << request_info.url << "\n"
774 << "Referrer = " << request_info.referrer.url;
777 const RequestExtraData kEmptyData;
778 const RequestExtraData* extra_data;
779 if (request_info.extra_data)
780 extra_data = static_cast<RequestExtraData*>(request_info.extra_data);
781 else
782 extra_data = &kEmptyData;
783 request->visiblity_state = extra_data->visibility_state();
784 request->render_frame_id = extra_data->render_frame_id();
785 request->is_main_frame = extra_data->is_main_frame();
786 request->parent_is_main_frame = extra_data->parent_is_main_frame();
787 request->parent_render_frame_id = extra_data->parent_render_frame_id();
788 request->allow_download = extra_data->allow_download();
789 request->transition_type = extra_data->transition_type();
790 request->should_replace_current_entry =
791 extra_data->should_replace_current_entry();
792 request->transferred_request_child_id =
793 extra_data->transferred_request_child_id();
794 request->transferred_request_request_id =
795 extra_data->transferred_request_request_id();
796 request->service_worker_provider_id =
797 extra_data->service_worker_provider_id();
798 request->request_body = request_body;
799 if (frame_origin)
800 *frame_origin = extra_data->frame_origin();
801 return request.Pass();
804 } // namespace content