OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc
e-loading | 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc
e-loading |
6 | 6 |
7 #include "content/common/resource_dispatcher.h" | 7 #include "content/common/resource_dispatcher.h" |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/shared_memory.h" | 14 #include "base/shared_memory.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "content/common/inter_process_time_ticks_converter.h" |
16 #include "content/common/request_extra_data.h" | 17 #include "content/common/request_extra_data.h" |
17 #include "content/common/resource_messages.h" | 18 #include "content/common/resource_messages.h" |
18 #include "content/public/common/resource_dispatcher_delegate.h" | 19 #include "content/public/common/resource_dispatcher_delegate.h" |
19 #include "content/public/common/resource_response.h" | 20 #include "content/public/common/resource_response.h" |
20 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
21 #include "net/base/net_util.h" | 22 #include "net/base/net_util.h" |
22 #include "net/base/upload_data.h" | 23 #include "net/base/upload_data.h" |
23 #include "net/http/http_response_headers.h" | 24 #include "net/http/http_response_headers.h" |
24 #include "webkit/glue/resource_type.h" | 25 #include "webkit/glue/resource_type.h" |
25 | 26 |
| 27 using content::InterProcessTimeTicksConverter; |
| 28 using content::LocalTimeDelta; |
| 29 using content::LocalTimeTicks; |
| 30 using content::RemoteTimeDelta; |
| 31 using content::RemoteTimeTicks; |
| 32 |
26 // Each resource request is assigned an ID scoped to this process. | 33 // Each resource request is assigned an ID scoped to this process. |
27 static int MakeRequestID() { | 34 static int MakeRequestID() { |
28 // NOTE: The resource_dispatcher_host also needs probably unique | 35 // NOTE: The resource_dispatcher_host also needs probably unique |
29 // request_ids, so they count down from -2 (-1 is a special we're | 36 // request_ids, so they count down from -2 (-1 is a special we're |
30 // screwed value), while the renderer process counts up. | 37 // screwed value), while the renderer process counts up. |
31 static int next_request_id = 0; | 38 static int next_request_id = 0; |
32 return next_request_id++; | 39 return next_request_id++; |
33 } | 40 } |
34 | 41 |
35 // ResourceLoaderBridge implementation ---------------------------------------- | 42 // ResourceLoaderBridge implementation ---------------------------------------- |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 // Acknowledge receipt | 348 // Acknowledge receipt |
342 message_sender()->Send( | 349 message_sender()->Send( |
343 new ResourceHostMsg_UploadProgress_ACK(message.routing_id(), request_id)); | 350 new ResourceHostMsg_UploadProgress_ACK(message.routing_id(), request_id)); |
344 } | 351 } |
345 | 352 |
346 void ResourceDispatcher::OnReceivedResponse( | 353 void ResourceDispatcher::OnReceivedResponse( |
347 int request_id, const content::ResourceResponseHead& response_head) { | 354 int request_id, const content::ResourceResponseHead& response_head) { |
348 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); | 355 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); |
349 if (!request_info) | 356 if (!request_info) |
350 return; | 357 return; |
| 358 request_info->response_start = base::TimeTicks::Now(); |
351 | 359 |
352 if (delegate_) { | 360 if (delegate_) { |
353 webkit_glue::ResourceLoaderBridge::Peer* new_peer = | 361 webkit_glue::ResourceLoaderBridge::Peer* new_peer = |
354 delegate_->OnReceivedResponse( | 362 delegate_->OnReceivedResponse( |
355 request_info->peer, response_head.mime_type, request_info->url); | 363 request_info->peer, response_head.mime_type, request_info->url); |
356 if (new_peer) | 364 if (new_peer) |
357 request_info->peer = new_peer; | 365 request_info->peer = new_peer; |
358 } | 366 } |
359 | 367 |
360 request_info->peer->OnReceivedResponse(response_head); | 368 webkit_glue::ResourceResponseInfo renderer_response_info; |
| 369 ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); |
| 370 request_info->peer->OnReceivedResponse(renderer_response_info); |
361 } | 371 } |
362 | 372 |
363 void ResourceDispatcher::OnReceivedCachedMetadata( | 373 void ResourceDispatcher::OnReceivedCachedMetadata( |
364 int request_id, const std::vector<char>& data) { | 374 int request_id, const std::vector<char>& data) { |
365 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); | 375 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); |
366 if (!request_info) | 376 if (!request_info) |
367 return; | 377 return; |
368 | 378 |
369 if (data.size()) | 379 if (data.size()) |
370 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size()); | 380 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 if (!request_info) | 414 if (!request_info) |
405 return; | 415 return; |
406 | 416 |
407 request_info->peer->OnDownloadedData(data_len); | 417 request_info->peer->OnDownloadedData(data_len); |
408 } | 418 } |
409 | 419 |
410 void ResourceDispatcher::OnReceivedRedirect( | 420 void ResourceDispatcher::OnReceivedRedirect( |
411 const IPC::Message& message, | 421 const IPC::Message& message, |
412 int request_id, | 422 int request_id, |
413 const GURL& new_url, | 423 const GURL& new_url, |
414 const webkit_glue::ResourceResponseInfo& info) { | 424 const content::ResourceResponseHead& response_head) { |
415 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); | 425 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); |
416 if (!request_info) | 426 if (!request_info) |
417 return; | 427 return; |
| 428 request_info->response_start = base::TimeTicks::Now(); |
418 | 429 |
419 int32 routing_id = message.routing_id(); | 430 int32 routing_id = message.routing_id(); |
420 bool has_new_first_party_for_cookies = false; | 431 bool has_new_first_party_for_cookies = false; |
421 GURL new_first_party_for_cookies; | 432 GURL new_first_party_for_cookies; |
422 if (request_info->peer->OnReceivedRedirect(new_url, info, | 433 webkit_glue::ResourceResponseInfo renderer_response_info; |
423 &has_new_first_party_for_cookies, | 434 ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); |
424 &new_first_party_for_cookies)) { | 435 if (request_info->peer->OnReceivedRedirect(new_url, renderer_response_info, |
| 436 &has_new_first_party_for_cookies, |
| 437 &new_first_party_for_cookies)) { |
425 // Double-check if the request is still around. The call above could | 438 // Double-check if the request is still around. The call above could |
426 // potentially remove it. | 439 // potentially remove it. |
427 request_info = GetPendingRequestInfo(request_id); | 440 request_info = GetPendingRequestInfo(request_id); |
428 if (!request_info) | 441 if (!request_info) |
429 return; | 442 return; |
430 request_info->pending_redirect_message.reset( | 443 request_info->pending_redirect_message.reset( |
431 new ResourceHostMsg_FollowRedirect(routing_id, request_id, | 444 new ResourceHostMsg_FollowRedirect(routing_id, request_id, |
432 has_new_first_party_for_cookies, | 445 has_new_first_party_for_cookies, |
433 new_first_party_for_cookies)); | 446 new_first_party_for_cookies)); |
434 if (!request_info->is_deferred) { | 447 if (!request_info->is_deferred) { |
435 FollowPendingRedirect(request_id, *request_info); | 448 FollowPendingRedirect(request_id, *request_info); |
436 } | 449 } |
437 } else { | 450 } else { |
438 CancelPendingRequest(routing_id, request_id); | 451 CancelPendingRequest(routing_id, request_id); |
439 } | 452 } |
440 } | 453 } |
441 | 454 |
442 void ResourceDispatcher::FollowPendingRedirect( | 455 void ResourceDispatcher::FollowPendingRedirect( |
443 int request_id, | 456 int request_id, |
444 PendingRequestInfo& request_info) { | 457 PendingRequestInfo& request_info) { |
445 IPC::Message* msg = request_info.pending_redirect_message.release(); | 458 IPC::Message* msg = request_info.pending_redirect_message.release(); |
446 if (msg) | 459 if (msg) |
447 message_sender()->Send(msg); | 460 message_sender()->Send(msg); |
448 } | 461 } |
449 | 462 |
450 void ResourceDispatcher::OnRequestComplete(int request_id, | 463 void ResourceDispatcher::OnRequestComplete( |
451 const net::URLRequestStatus& status, | 464 int request_id, |
452 const std::string& security_info, | 465 const net::URLRequestStatus& status, |
453 const base::Time& completion_time) { | 466 const std::string& security_info, |
| 467 const base::TimeTicks& browser_completion_time) { |
454 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); | 468 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); |
455 if (!request_info) | 469 if (!request_info) |
456 return; | 470 return; |
| 471 request_info->completion_time = base::TimeTicks::Now(); |
457 | 472 |
458 webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer; | 473 webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer; |
459 | 474 |
460 if (delegate_) { | 475 if (delegate_) { |
461 webkit_glue::ResourceLoaderBridge::Peer* new_peer = | 476 webkit_glue::ResourceLoaderBridge::Peer* new_peer = |
462 delegate_->OnRequestComplete( | 477 delegate_->OnRequestComplete( |
463 request_info->peer, request_info->resource_type, status); | 478 request_info->peer, request_info->resource_type, status); |
464 if (new_peer) | 479 if (new_peer) |
465 request_info->peer = new_peer; | 480 request_info->peer = new_peer; |
466 } | 481 } |
467 | 482 |
| 483 base::TimeTicks renderer_completion_time = ToRendererCompletionTime( |
| 484 *request_info, browser_completion_time); |
468 // The request ID will be removed from our pending list in the destructor. | 485 // The request ID will be removed from our pending list in the destructor. |
469 // Normally, dispatching this message causes the reference-counted request to | 486 // Normally, dispatching this message causes the reference-counted request to |
470 // die immediately. | 487 // die immediately. |
471 peer->OnCompletedRequest(status, security_info, completion_time); | 488 peer->OnCompletedRequest(status, security_info, renderer_completion_time); |
472 } | 489 } |
473 | 490 |
474 int ResourceDispatcher::AddPendingRequest( | 491 int ResourceDispatcher::AddPendingRequest( |
475 webkit_glue::ResourceLoaderBridge::Peer* callback, | 492 webkit_glue::ResourceLoaderBridge::Peer* callback, |
476 ResourceType::Type resource_type, | 493 ResourceType::Type resource_type, |
477 const GURL& request_url) { | 494 const GURL& request_url) { |
478 // Compute a unique request_id for this renderer process. | 495 // Compute a unique request_id for this renderer process. |
479 int id = MakeRequestID(); | 496 int id = MakeRequestID(); |
480 pending_requests_[id] = | 497 pending_requests_[id] = |
481 PendingRequestInfo(callback, resource_type, request_url); | 498 PendingRequestInfo(callback, resource_type, request_url); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 } | 589 } |
573 } | 590 } |
574 } | 591 } |
575 } | 592 } |
576 | 593 |
577 webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( | 594 webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( |
578 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { | 595 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { |
579 return new webkit_glue::IPCResourceLoaderBridge(this, request_info); | 596 return new webkit_glue::IPCResourceLoaderBridge(this, request_info); |
580 } | 597 } |
581 | 598 |
| 599 void ResourceDispatcher::ToResourceResponseInfo( |
| 600 const PendingRequestInfo& request_info, |
| 601 const content::ResourceResponseHead& browser_info, |
| 602 webkit_glue::ResourceResponseInfo* renderer_info) const { |
| 603 *renderer_info = browser_info; |
| 604 if (request_info.request_start.is_null() || |
| 605 request_info.response_start.is_null() || |
| 606 browser_info.request_start.is_null() || |
| 607 browser_info.response_start.is_null()) { |
| 608 return; |
| 609 } |
| 610 content::InterProcessTimeTicksConverter converter( |
| 611 LocalTimeTicks::FromTimeTicks(request_info.request_start), |
| 612 LocalTimeTicks::FromTimeTicks(request_info.response_start), |
| 613 RemoteTimeTicks::FromTimeTicks(browser_info.request_start), |
| 614 RemoteTimeTicks::FromTimeTicks(browser_info.response_start)); |
| 615 |
| 616 LocalTimeTicks renderer_base_ticks = converter.ToLocalTimeTicks( |
| 617 RemoteTimeTicks::FromTimeTicks(browser_info.load_timing.base_ticks)); |
| 618 renderer_info->load_timing.base_ticks = renderer_base_ticks.ToTimeTicks(); |
| 619 |
| 620 #define CONVERT(field) \ |
| 621 LocalTimeDelta renderer_##field = converter.ToLocalTimeDelta( \ |
| 622 RemoteTimeDelta::FromRawDelta(browser_info.load_timing.field)); \ |
| 623 renderer_info->load_timing.field = renderer_##field.ToInt32() |
| 624 |
| 625 CONVERT(proxy_start); |
| 626 CONVERT(dns_start); |
| 627 CONVERT(dns_end); |
| 628 CONVERT(connect_start); |
| 629 CONVERT(connect_end); |
| 630 CONVERT(ssl_start); |
| 631 CONVERT(ssl_end); |
| 632 CONVERT(send_start); |
| 633 CONVERT(send_end); |
| 634 CONVERT(receive_headers_start); |
| 635 CONVERT(receive_headers_end); |
| 636 |
| 637 #undef CONVERT |
| 638 } |
| 639 |
| 640 base::TimeTicks ResourceDispatcher::ToRendererCompletionTime( |
| 641 const PendingRequestInfo& request_info, |
| 642 const base::TimeTicks& browser_completion_time) const { |
| 643 if (request_info.completion_time.is_null()) { |
| 644 return browser_completion_time; |
| 645 } |
| 646 |
| 647 // TODO(simonjam): The optimal lower bound should be the most recent value of |
| 648 // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that? |
| 649 // Until then, |response_start| is used as it is the most recent value |
| 650 // returned for this request. |
| 651 int64 result = std::max(browser_completion_time.ToInternalValue(), |
| 652 request_info.response_start.ToInternalValue()); |
| 653 result = std::min(result, request_info.completion_time.ToInternalValue()); |
| 654 return base::TimeTicks::FromInternalValue(result); |
| 655 } |
| 656 |
| 657 // static |
582 bool ResourceDispatcher::IsResourceDispatcherMessage( | 658 bool ResourceDispatcher::IsResourceDispatcherMessage( |
583 const IPC::Message& message) { | 659 const IPC::Message& message) { |
584 switch (message.type()) { | 660 switch (message.type()) { |
585 case ResourceMsg_UploadProgress::ID: | 661 case ResourceMsg_UploadProgress::ID: |
586 case ResourceMsg_ReceivedResponse::ID: | 662 case ResourceMsg_ReceivedResponse::ID: |
587 case ResourceMsg_ReceivedCachedMetadata::ID: | 663 case ResourceMsg_ReceivedCachedMetadata::ID: |
588 case ResourceMsg_ReceivedRedirect::ID: | 664 case ResourceMsg_ReceivedRedirect::ID: |
589 case ResourceMsg_DataReceived::ID: | 665 case ResourceMsg_DataReceived::ID: |
590 case ResourceMsg_DataDownloaded::ID: | 666 case ResourceMsg_DataDownloaded::ID: |
591 case ResourceMsg_RequestComplete::ID: | 667 case ResourceMsg_RequestComplete::ID: |
(...skipping 30 matching lines...) Expand all Loading... |
622 | 698 |
623 // static | 699 // static |
624 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { | 700 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { |
625 while (!queue->empty()) { | 701 while (!queue->empty()) { |
626 IPC::Message* message = queue->front(); | 702 IPC::Message* message = queue->front(); |
627 ReleaseResourcesInDataMessage(*message); | 703 ReleaseResourcesInDataMessage(*message); |
628 queue->pop_front(); | 704 queue->pop_front(); |
629 delete message; | 705 delete message; |
630 } | 706 } |
631 } | 707 } |
OLD | NEW |