chrome/browser/extensions: Remove use of MessageLoopProxy and deprecated MessageLoop...
[chromium-blink-merge.git] / content / child / resource_dispatcher.cc
blobaa6577eb60393026dbf78b79d5dc74d78969cfd5
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"
37 namespace content {
39 namespace {
41 // Converts |time| from a remote to local TimeTicks, overwriting the original
42 // value.
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() {
51 #if defined(OS_WIN)
52 DWORD last_err = GetLastError();
53 base::debug::Alias(&last_err);
54 #endif
55 CHECK(false);
58 // Each resource request is assigned an ID scoped to this process.
59 int MakeRequestID() {
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++;
67 } // namespace
69 ResourceDispatcher::ResourceDispatcher(
70 IPC::Sender* sender,
71 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
72 : message_sender_(sender),
73 delegate_(NULL),
74 io_timestamp_(base::TimeTicks()),
75 main_thread_task_runner_(main_thread_task_runner),
76 weak_factory_(this) {
79 ResourceDispatcher::~ResourceDispatcher() {
82 bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
83 if (!IsResourceDispatcherMessage(message)) {
84 return false;
87 int request_id;
89 base::PickleIterator iter(message);
90 if (!iter.ReadInt(&request_id)) {
91 NOTREACHED() << "malformed resource message";
92 return true;
95 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
96 if (!request_info) {
97 // Release resources in the message if it is a data message.
98 ReleaseResourcesInDataMessage(message);
99 return true;
102 if (request_info->is_deferred) {
103 request_info->deferred_message_queue.push_back(new IPC::Message(message));
104 return true;
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));
115 return true;
119 DispatchMessage(message);
120 return true;
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.
128 return NULL;
130 return &(it->second);
133 void ResourceDispatcher::OnUploadProgress(int request_id, int64 position,
134 int64 size) {
135 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
136 if (!request_info)
137 return;
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);
149 if (!request_info)
150 return;
151 request_info->response_start = ConsumeIOTimestamp();
153 if (delegate_) {
154 RequestPeer* new_peer =
155 delegate_->OnReceivedResponse(
156 request_info->peer, response_head.mime_type, request_info->url);
157 if (new_peer)
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);
175 if (!request_info)
176 return;
178 if (data.size())
179 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
182 void ResourceDispatcher::OnSetDataBuffer(int request_id,
183 base::SharedMemoryHandle shm_handle,
184 int shm_size,
185 base::ProcessId renderer_pid) {
186 TRACE_EVENT0("loader", "ResourceDispatcher::OnSetDataBuffer");
187 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
188 if (!request_info)
189 return;
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);
201 if (!ok) {
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);
209 CrashOnMapFailure();
210 return;
213 request_info->buffer_size = shm_size;
216 void ResourceDispatcher::OnReceivedData(int request_id,
217 int data_offset,
218 int data_length,
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());
237 CHECK(data_start);
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,
247 &alternative_data);
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.
259 send_ack = false;
260 request_info->threaded_data_provider->OnReceivedDataOnForegroundThread(
261 data_ptr, data_length, encoded_data_length);
262 } else {
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()));
268 } else {
269 data = factory->Create(data_offset, data_length, encoded_data_length);
270 // |data| takes care of ACKing.
271 send_ack = false;
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.
282 if (send_ack)
283 message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id));
286 void ResourceDispatcher::OnDownloadedData(int request_id,
287 int data_len,
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);
293 if (!request_info)
294 return;
296 request_info->peer->OnDownloadedData(data_len, encoded_data_length);
299 void ResourceDispatcher::OnReceivedRedirect(
300 int request_id,
301 const net::RedirectInfo& redirect_info,
302 const ResourceResponseHead& response_head) {
303 TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedRedirect");
304 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
305 if (!request_info)
306 return;
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);
316 if (!request_info)
317 return;
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);
326 } else {
327 Cancel(request_id);
331 void ResourceDispatcher::FollowPendingRedirect(
332 int request_id,
333 PendingRequestInfo& request_info) {
334 IPC::Message* msg = request_info.pending_redirect_message.release();
335 if (msg)
336 message_sender_->Send(msg);
339 void ResourceDispatcher::OnRequestComplete(
340 int request_id,
341 const ResourceMsg_RequestCompleteData& request_complete_data) {
342 TRACE_EVENT0("loader", "ResourceDispatcher::OnRequestComplete");
344 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
345 if (!request_info)
346 return;
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;
356 if (delegate_) {
357 RequestPeer* new_peer =
358 delegate_->OnRequestComplete(
359 request_info->peer, request_info->resource_type,
360 request_complete_data.error_code);
361 if (new_peer)
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);
375 return;
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
380 // die immediately.
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(
390 int request_id,
391 const ResourceMsg_RequestCompleteData& request_complete_data,
392 const base::TimeTicks& renderer_completion_time) {
393 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
394 if (!request_info)
395 return;
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())
409 return false;
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));
423 return true;
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";
430 return;
433 // Cancel the request, and clean it up so the bridge will receive no more
434 // messages.
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";
443 return;
445 PendingRequestInfo& request_info = it->second;
446 if (value) {
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_);
477 return true;
480 return false;
483 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo()
484 : peer(NULL),
485 threaded_data_provider(NULL),
486 resource_type(RESOURCE_TYPE_SUB_RESOURCE),
487 is_deferred(false),
488 download_to_file(false),
489 blocked_response(false),
490 buffer_size(0) {
493 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
494 RequestPeer* peer,
495 ResourceType resource_type,
496 int origin_pid,
497 const GURL& frame_origin,
498 const GURL& request_url,
499 bool download_to_file)
500 : peer(peer),
501 threaded_data_provider(NULL),
502 resource_type(resource_type),
503 origin_pid(origin_pid),
504 is_deferred(false),
505 url(request_url),
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.
534 return;
535 PendingRequestInfo& request_info = it->second;
536 if (request_info.is_deferred)
537 return;
538 // Because message handlers could result in request_info being destroyed,
539 // we need to work with a stack reference to the deferred queue.
540 MessageQueue q;
541 q.swap(request_info.deferred_message_queue);
542 while (!q.empty()) {
543 IPC::Message* m = q.front();
544 q.pop_front();
545 DispatchMessage(*m);
546 delete m;
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);
556 return;
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;
575 return;
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,
594 RequestPeer* peer) {
595 GURL frame_origin;
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,
604 request->origin_pid,
605 frame_origin,
606 request->url,
607 request_info.download_to_file);
609 message_sender_->Send(new ResourceHostMsg_RequestResource(
610 request_info.routing_id, request_id, *request));
612 return request_id;
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()) {
625 return;
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()) {
655 UMA_HISTOGRAM_TIMES(
656 "InterProcessTimeTicks.BrowserAhead_BrowserToRenderer", skew);
657 } else {
658 UMA_HISTOGRAM_TIMES(
659 "InterProcessTimeTicks.BrowserBehind_BrowserToRenderer", -skew);
662 UMA_HISTOGRAM_BOOLEAN(
663 "InterProcessTimeTicks.IsSkewAdditive_BrowserToRenderer",
664 is_skew_additive);
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();
689 return result;
692 // static
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:
704 return true;
706 default:
707 break;
710 return false;
713 // static
714 void ResourceDispatcher::ReleaseResourcesInDataMessage(
715 const IPC::Message& message) {
716 base::PickleIterator iter(message);
717 int request_id;
718 if (!iter.ReadInt(&request_id)) {
719 NOTREACHED() << "malformed resource message";
720 return;
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,
728 &iter,
729 &shm_handle)) {
730 if (base::SharedMemory::IsHandleValid(shm_handle))
731 base::SharedMemory::CloseHandle(shm_handle);
736 // static
737 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
738 while (!queue->empty()) {
739 IPC::Message* message = queue->front();
740 ReleaseResourcesInDataMessage(*message);
741 queue->pop_front();
742 delete 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);
790 else
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;
808 if (frame_origin)
809 *frame_origin = extra_data->frame_origin();
810 return request.Pass();
813 } // namespace content