Chromium Code Reviews| 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 ConvertBrowserResponseToRendererResponse(*request_info, response_head); | |
| 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 ConvertBrowserResponseToRendererResponse(*request_info, response_head); |
| 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 = | |
| 484 ConvertBrowserCompletionToRendererCompletion(*request_info, | |
| 485 browser_completion_time); | |
| 468 // The request ID will be removed from our pending list in the destructor. | 486 // The request ID will be removed from our pending list in the destructor. |
| 469 // Normally, dispatching this message causes the reference-counted request to | 487 // Normally, dispatching this message causes the reference-counted request to |
| 470 // die immediately. | 488 // die immediately. |
| 471 peer->OnCompletedRequest(status, security_info, completion_time); | 489 peer->OnCompletedRequest(status, security_info, renderer_completion_time); |
| 472 } | 490 } |
| 473 | 491 |
| 474 int ResourceDispatcher::AddPendingRequest( | 492 int ResourceDispatcher::AddPendingRequest( |
| 475 webkit_glue::ResourceLoaderBridge::Peer* callback, | 493 webkit_glue::ResourceLoaderBridge::Peer* callback, |
| 476 ResourceType::Type resource_type, | 494 ResourceType::Type resource_type, |
| 477 const GURL& request_url) { | 495 const GURL& request_url) { |
| 478 // Compute a unique request_id for this renderer process. | 496 // Compute a unique request_id for this renderer process. |
| 479 int id = MakeRequestID(); | 497 int id = MakeRequestID(); |
| 480 pending_requests_[id] = | 498 pending_requests_[id] = |
| 481 PendingRequestInfo(callback, resource_type, request_url); | 499 PendingRequestInfo(callback, resource_type, request_url); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 572 } | 590 } |
| 573 } | 591 } |
| 574 } | 592 } |
| 575 } | 593 } |
| 576 | 594 |
| 577 webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( | 595 webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( |
| 578 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { | 596 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { |
| 579 return new webkit_glue::IPCResourceLoaderBridge(this, request_info); | 597 return new webkit_glue::IPCResourceLoaderBridge(this, request_info); |
| 580 } | 598 } |
| 581 | 599 |
| 600 webkit_glue::ResourceResponseInfo | |
| 601 ResourceDispatcher::ConvertBrowserResponseToRendererResponse( | |
|
darin (slow to review)
2011/12/12 22:25:46
nit: this seems like a good use case for an out-pa
James Simonsen
2011/12/12 23:35:34
Done.
| |
| 602 const PendingRequestInfo& request_info, | |
| 603 const content::ResourceResponseHead& browser_info) const { | |
| 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 browser_info; | |
| 609 } | |
| 610 webkit_glue::ResourceResponseInfo renderer_info = browser_info; | |
| 611 content::InterProcessTimeTicksConverter converter( | |
| 612 LocalTimeTicks::FromTimeTicks(request_info.request_start), | |
| 613 LocalTimeTicks::FromTimeTicks(request_info.response_start), | |
| 614 RemoteTimeTicks::FromTimeTicks(browser_info.request_start), | |
| 615 RemoteTimeTicks::FromTimeTicks(browser_info.response_start)); | |
| 616 | |
| 617 LocalTimeTicks renderer_base_ticks = converter.ConvertMilliseconds( | |
| 618 RemoteTimeTicks::FromTimeTicks(browser_info.load_timing.base_ticks)); | |
| 619 renderer_info.load_timing.base_ticks = renderer_base_ticks.ToTimeTicks(); | |
| 620 | |
| 621 #define CONVERT(field) \ | |
| 622 LocalTimeDelta renderer_##field = converter.ConvertDelta( \ | |
| 623 RemoteTimeDelta::FromRawDelta(browser_info.load_timing.field)); \ | |
| 624 renderer_info.load_timing.field = renderer_##field.ToInt32() | |
| 625 | |
| 626 CONVERT(proxy_start); | |
| 627 CONVERT(dns_start); | |
| 628 CONVERT(dns_end); | |
| 629 CONVERT(connect_start); | |
| 630 CONVERT(connect_end); | |
| 631 CONVERT(ssl_start); | |
| 632 CONVERT(ssl_end); | |
| 633 CONVERT(send_start); | |
| 634 CONVERT(send_end); | |
| 635 CONVERT(receive_headers_start); | |
| 636 CONVERT(receive_headers_end); | |
| 637 | |
| 638 #undef CONVERT | |
| 639 | |
| 640 return renderer_info; | |
| 641 } | |
| 642 | |
| 643 base::TimeTicks | |
| 644 ResourceDispatcher::ConvertBrowserCompletionToRendererCompletion( | |
|
darin (slow to review)
2011/12/12 22:25:46
nit: maybe just shorten this function named down t
James Simonsen
2011/12/12 23:35:34
Done.
| |
| 645 const PendingRequestInfo& request_info, | |
| 646 const base::TimeTicks& browser_completion_time) const { | |
| 647 if (request_info.completion_time.is_null()) { | |
| 648 return browser_completion_time; | |
| 649 } | |
| 650 | |
| 651 // TODO(simonjam): The optimal lower bound should be the most recent value of | |
| 652 // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that? | |
| 653 // Until then, |response_start| is used as it is the most recent value | |
| 654 // returned for this request. | |
| 655 LocalTimeTicks renderer_completion_time = | |
| 656 content::InterProcessTimeTicksConverter::ClampTimeInRange( | |
| 657 RemoteTimeTicks::FromTimeTicks(browser_completion_time), | |
| 658 LocalTimeTicks::FromTimeTicks(request_info.response_start), | |
| 659 LocalTimeTicks::FromTimeTicks(request_info.completion_time)); | |
| 660 return renderer_completion_time.ToTimeTicks(); | |
| 661 } | |
| 662 | |
| 663 // static | |
| 582 bool ResourceDispatcher::IsResourceDispatcherMessage( | 664 bool ResourceDispatcher::IsResourceDispatcherMessage( |
| 583 const IPC::Message& message) { | 665 const IPC::Message& message) { |
| 584 switch (message.type()) { | 666 switch (message.type()) { |
| 585 case ResourceMsg_UploadProgress::ID: | 667 case ResourceMsg_UploadProgress::ID: |
| 586 case ResourceMsg_ReceivedResponse::ID: | 668 case ResourceMsg_ReceivedResponse::ID: |
| 587 case ResourceMsg_ReceivedCachedMetadata::ID: | 669 case ResourceMsg_ReceivedCachedMetadata::ID: |
| 588 case ResourceMsg_ReceivedRedirect::ID: | 670 case ResourceMsg_ReceivedRedirect::ID: |
| 589 case ResourceMsg_DataReceived::ID: | 671 case ResourceMsg_DataReceived::ID: |
| 590 case ResourceMsg_DataDownloaded::ID: | 672 case ResourceMsg_DataDownloaded::ID: |
| 591 case ResourceMsg_RequestComplete::ID: | 673 case ResourceMsg_RequestComplete::ID: |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 622 | 704 |
| 623 // static | 705 // static |
| 624 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { | 706 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { |
| 625 while (!queue->empty()) { | 707 while (!queue->empty()) { |
| 626 IPC::Message* message = queue->front(); | 708 IPC::Message* message = queue->front(); |
| 627 ReleaseResourcesInDataMessage(*message); | 709 ReleaseResourcesInDataMessage(*message); |
| 628 queue->pop_front(); | 710 queue->pop_front(); |
| 629 delete message; | 711 delete message; |
| 630 } | 712 } |
| 631 } | 713 } |
| OLD | NEW |