Home | History | Annotate | Download | only in child
      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.
      4 
      5 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
      6 
      7 #include "content/child/resource_dispatcher.h"
      8 
      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/files/file_path.h"
     14 #include "base/memory/shared_memory.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/metrics/histogram.h"
     17 #include "base/strings/string_util.h"
     18 #include "content/child/request_extra_data.h"
     19 #include "content/common/inter_process_time_ticks_converter.h"
     20 #include "content/common/resource_messages.h"
     21 #include "content/public/child/resource_dispatcher_delegate.h"
     22 #include "content/public/common/resource_response.h"
     23 #include "net/base/net_errors.h"
     24 #include "net/base/net_util.h"
     25 #include "net/base/request_priority.h"
     26 #include "net/http/http_response_headers.h"
     27 #include "webkit/common/resource_type.h"
     28 
     29 using webkit_glue::ResourceLoaderBridge;
     30 using webkit_glue::ResourceRequestBody;
     31 using webkit_glue::ResourceResponseInfo;
     32 
     33 namespace content {
     34 
     35 namespace {
     36 
     37 // Converts |time| from a remote to local TimeTicks, overwriting the original
     38 // value.
     39 void RemoteToLocalTimeTicks(
     40     const InterProcessTimeTicksConverter& converter,
     41     base::TimeTicks* time) {
     42   RemoteTimeTicks remote_time = RemoteTimeTicks::FromTimeTicks(*time);
     43   *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
     44 }
     45 
     46 
     47 }  // namespace
     48 
     49 static void CrashOnMapFailure() {
     50 #if defined(OS_WIN)
     51   DWORD last_err = GetLastError();
     52   base::debug::Alias(&last_err);
     53 #endif
     54   CHECK(false);
     55 }
     56 
     57 // Each resource request is assigned an ID scoped to this process.
     58 static int MakeRequestID() {
     59   // NOTE: The resource_dispatcher_host also needs probably unique
     60   // request_ids, so they count down from -2 (-1 is a special we're
     61   // screwed value), while the renderer process counts up.
     62   static int next_request_id = 0;
     63   return next_request_id++;
     64 }
     65 
     66 // ResourceLoaderBridge implementation ----------------------------------------
     67 
     68 class IPCResourceLoaderBridge : public ResourceLoaderBridge {
     69  public:
     70   IPCResourceLoaderBridge(ResourceDispatcher* dispatcher,
     71       const ResourceLoaderBridge::RequestInfo& request_info);
     72   virtual ~IPCResourceLoaderBridge();
     73 
     74   // ResourceLoaderBridge
     75   virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE;
     76   virtual bool Start(Peer* peer) OVERRIDE;
     77   virtual void Cancel() OVERRIDE;
     78   virtual void SetDefersLoading(bool value) OVERRIDE;
     79   virtual void DidChangePriority(net::RequestPriority new_priority) OVERRIDE;
     80   virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE;
     81 
     82  private:
     83   ResourceLoaderBridge::Peer* peer_;
     84 
     85   // The resource dispatcher for this loader.  The bridge doesn't own it, but
     86   // it's guaranteed to outlive the bridge.
     87   ResourceDispatcher* dispatcher_;
     88 
     89   // The request to send, created on initialization for modification and
     90   // appending data.
     91   ResourceHostMsg_Request request_;
     92 
     93   // ID for the request, valid once Start()ed, -1 if not valid yet.
     94   int request_id_;
     95 
     96   // The routing id used when sending IPC messages.
     97   int routing_id_;
     98 
     99   bool is_synchronous_request_;
    100 };
    101 
    102 IPCResourceLoaderBridge::IPCResourceLoaderBridge(
    103     ResourceDispatcher* dispatcher,
    104     const ResourceLoaderBridge::RequestInfo& request_info)
    105     : peer_(NULL),
    106       dispatcher_(dispatcher),
    107       request_id_(-1),
    108       routing_id_(request_info.routing_id),
    109       is_synchronous_request_(false) {
    110   DCHECK(dispatcher_) << "no resource dispatcher";
    111   request_.method = request_info.method;
    112   request_.url = request_info.url;
    113   request_.first_party_for_cookies = request_info.first_party_for_cookies;
    114   request_.referrer = request_info.referrer;
    115   request_.referrer_policy = request_info.referrer_policy;
    116   request_.headers = request_info.headers;
    117   request_.load_flags = request_info.load_flags;
    118   request_.origin_pid = request_info.requestor_pid;
    119   request_.resource_type = request_info.request_type;
    120   request_.priority = request_info.priority;
    121   request_.request_context = request_info.request_context;
    122   request_.appcache_host_id = request_info.appcache_host_id;
    123   request_.download_to_file = request_info.download_to_file;
    124   request_.has_user_gesture = request_info.has_user_gesture;
    125   if (request_info.extra_data) {
    126     RequestExtraData* extra_data =
    127         static_cast<RequestExtraData*>(request_info.extra_data);
    128     request_.is_main_frame = extra_data->is_main_frame();
    129     request_.frame_id = extra_data->frame_id();
    130     request_.parent_is_main_frame = extra_data->parent_is_main_frame();
    131     request_.parent_frame_id = extra_data->parent_frame_id();
    132     request_.allow_download = extra_data->allow_download();
    133     request_.transition_type = extra_data->transition_type();
    134     request_.transferred_request_child_id =
    135         extra_data->transferred_request_child_id();
    136     request_.transferred_request_request_id =
    137         extra_data->transferred_request_request_id();
    138   } else {
    139     request_.is_main_frame = false;
    140     request_.frame_id = -1;
    141     request_.parent_is_main_frame = false;
    142     request_.parent_frame_id = -1;
    143     request_.allow_download = true;
    144     request_.transition_type = PAGE_TRANSITION_LINK;
    145     request_.transferred_request_child_id = -1;
    146     request_.transferred_request_request_id = -1;
    147   }
    148 }
    149 
    150 IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
    151   // we remove our hook for the resource dispatcher only when going away, since
    152   // it doesn't keep track of whether we've force terminated the request
    153   if (request_id_ >= 0) {
    154     // this operation may fail, as the dispatcher will have preemptively
    155     // removed us when the renderer sends the ReceivedAllData message.
    156     dispatcher_->RemovePendingRequest(request_id_);
    157 
    158     if (request_.download_to_file) {
    159       dispatcher_->message_sender()->Send(
    160           new ResourceHostMsg_ReleaseDownloadedFile(request_id_));
    161     }
    162   }
    163 }
    164 
    165 void IPCResourceLoaderBridge::SetRequestBody(
    166     ResourceRequestBody* request_body) {
    167   DCHECK(request_id_ == -1) << "request already started";
    168   request_.request_body = request_body;
    169 }
    170 
    171 // Writes a footer on the message and sends it
    172 bool IPCResourceLoaderBridge::Start(Peer* peer) {
    173   if (request_id_ != -1) {
    174     NOTREACHED() << "Starting a request twice";
    175     return false;
    176   }
    177 
    178   peer_ = peer;
    179 
    180   // generate the request ID, and append it to the message
    181   request_id_ = dispatcher_->AddPendingRequest(
    182       peer_, request_.resource_type, request_.url);
    183 
    184   return dispatcher_->message_sender()->Send(
    185       new ResourceHostMsg_RequestResource(routing_id_, request_id_, request_));
    186 }
    187 
    188 void IPCResourceLoaderBridge::Cancel() {
    189   if (request_id_ < 0) {
    190     NOTREACHED() << "Trying to cancel an unstarted request";
    191     return;
    192   }
    193 
    194   if (!is_synchronous_request_)
    195     dispatcher_->CancelPendingRequest(routing_id_, request_id_);
    196 
    197   // We can't remove the request ID from the resource dispatcher because more
    198   // data might be pending. Sending the cancel message may cause more data
    199   // to be flushed, and will then cause a complete message to be sent.
    200 }
    201 
    202 void IPCResourceLoaderBridge::SetDefersLoading(bool value) {
    203   if (request_id_ < 0) {
    204     NOTREACHED() << "Trying to (un)defer an unstarted request";
    205     return;
    206   }
    207 
    208   dispatcher_->SetDefersLoading(request_id_, value);
    209 }
    210 
    211 void IPCResourceLoaderBridge::DidChangePriority(
    212     net::RequestPriority new_priority) {
    213   if (request_id_ < 0) {
    214     NOTREACHED() << "Trying to change priority of an unstarted request";
    215     return;
    216   }
    217 
    218   dispatcher_->DidChangePriority(routing_id_, request_id_, new_priority);
    219 }
    220 
    221 void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
    222   if (request_id_ != -1) {
    223     NOTREACHED() << "Starting a request twice";
    224     response->error_code = net::ERR_FAILED;
    225     return;
    226   }
    227 
    228   request_id_ = MakeRequestID();
    229   is_synchronous_request_ = true;
    230 
    231   SyncLoadResult result;
    232   IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(routing_id_, request_id_,
    233                                                        request_, &result);
    234   // NOTE: This may pump events (see RenderThread::Send).
    235   if (!dispatcher_->message_sender()->Send(msg)) {
    236     response->error_code = net::ERR_FAILED;
    237     return;
    238   }
    239 
    240   response->error_code = result.error_code;
    241   response->url = result.final_url;
    242   response->headers = result.headers;
    243   response->mime_type = result.mime_type;
    244   response->charset = result.charset;
    245   response->request_time = result.request_time;
    246   response->response_time = result.response_time;
    247   response->encoded_data_length = result.encoded_data_length;
    248   response->load_timing = result.load_timing;
    249   response->devtools_info = result.devtools_info;
    250   response->data.swap(result.data);
    251   response->download_file_path = result.download_file_path;
    252 }
    253 
    254 // ResourceDispatcher ---------------------------------------------------------
    255 
    256 ResourceDispatcher::ResourceDispatcher(IPC::Sender* sender)
    257     : message_sender_(sender),
    258       weak_factory_(this),
    259       delegate_(NULL),
    260       io_timestamp_(base::TimeTicks()) {
    261 }
    262 
    263 ResourceDispatcher::~ResourceDispatcher() {
    264 }
    265 
    266 // ResourceDispatcher implementation ------------------------------------------
    267 
    268 bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
    269   if (!IsResourceDispatcherMessage(message)) {
    270     return false;
    271   }
    272 
    273   int request_id;
    274 
    275   PickleIterator iter(message);
    276   if (!message.ReadInt(&iter, &request_id)) {
    277     NOTREACHED() << "malformed resource message";
    278     return true;
    279   }
    280 
    281   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    282   if (!request_info) {
    283     // Release resources in the message if it is a data message.
    284     ReleaseResourcesInDataMessage(message);
    285     return true;
    286   }
    287 
    288   if (request_info->is_deferred) {
    289     request_info->deferred_message_queue.push_back(new IPC::Message(message));
    290     return true;
    291   }
    292   // Make sure any deferred messages are dispatched before we dispatch more.
    293   if (!request_info->deferred_message_queue.empty()) {
    294     FlushDeferredMessages(request_id);
    295     // The request could have been deferred now. If yes then the current
    296     // message has to be queued up. The request_info instance should remain
    297     // valid here as there are pending messages for it.
    298     DCHECK(pending_requests_.find(request_id) != pending_requests_.end());
    299     if (request_info->is_deferred) {
    300       request_info->deferred_message_queue.push_back(new IPC::Message(message));
    301       return true;
    302     }
    303   }
    304 
    305   DispatchMessage(message);
    306   return true;
    307 }
    308 
    309 ResourceDispatcher::PendingRequestInfo*
    310 ResourceDispatcher::GetPendingRequestInfo(int request_id) {
    311   PendingRequestList::iterator it = pending_requests_.find(request_id);
    312   if (it == pending_requests_.end()) {
    313     // This might happen for kill()ed requests on the webkit end.
    314     return NULL;
    315   }
    316   return &(it->second);
    317 }
    318 
    319 void ResourceDispatcher::OnUploadProgress(
    320     const IPC::Message& message, int request_id, int64 position, int64 size) {
    321   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    322   if (!request_info)
    323     return;
    324 
    325   request_info->peer->OnUploadProgress(position, size);
    326 
    327   // Acknowledge receipt
    328   message_sender()->Send(
    329       new ResourceHostMsg_UploadProgress_ACK(message.routing_id(), request_id));
    330 }
    331 
    332 void ResourceDispatcher::OnReceivedResponse(
    333     int request_id, const ResourceResponseHead& response_head) {
    334   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    335   if (!request_info)
    336     return;
    337   request_info->response_start = ConsumeIOTimestamp();
    338 
    339   if (delegate_) {
    340     ResourceLoaderBridge::Peer* new_peer =
    341         delegate_->OnReceivedResponse(
    342             request_info->peer, response_head.mime_type, request_info->url);
    343     if (new_peer)
    344       request_info->peer = new_peer;
    345   }
    346 
    347   ResourceResponseInfo renderer_response_info;
    348   ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
    349   request_info->peer->OnReceivedResponse(renderer_response_info);
    350 }
    351 
    352 void ResourceDispatcher::OnReceivedCachedMetadata(
    353       int request_id, const std::vector<char>& data) {
    354   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    355   if (!request_info)
    356     return;
    357 
    358   if (data.size())
    359     request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
    360 }
    361 
    362 void ResourceDispatcher::OnSetDataBuffer(const IPC::Message& message,
    363                                          int request_id,
    364                                          base::SharedMemoryHandle shm_handle,
    365                                          int shm_size,
    366                                          base::ProcessId renderer_pid) {
    367   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    368   if (!request_info)
    369     return;
    370 
    371   bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle);
    372   CHECK((shm_valid && shm_size > 0) || (!shm_valid && !shm_size));
    373 
    374   request_info->buffer.reset(
    375       new base::SharedMemory(shm_handle, true));  // read only
    376 
    377   bool ok = request_info->buffer->Map(shm_size);
    378   if (!ok) {
    379     // Added to help debug crbug/160401.
    380     base::ProcessId renderer_pid_copy = renderer_pid;
    381     base::debug::Alias(&renderer_pid_copy);
    382 
    383     base::SharedMemoryHandle shm_handle_copy = shm_handle;
    384     base::debug::Alias(&shm_handle_copy);
    385 
    386     CrashOnMapFailure();
    387     return;
    388   }
    389 
    390   request_info->buffer_size = shm_size;
    391 }
    392 
    393 void ResourceDispatcher::OnReceivedData(const IPC::Message& message,
    394                                         int request_id,
    395                                         int data_offset,
    396                                         int data_length,
    397                                         int encoded_data_length) {
    398   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    399   if (request_info && data_length > 0) {
    400     CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle()));
    401     CHECK_GE(request_info->buffer_size, data_offset + data_length);
    402 
    403     // Ensure that the SHM buffer remains valid for the duration of this scope.
    404     // It is possible for CancelPendingRequest() to be called before we exit
    405     // this scope.
    406     linked_ptr<base::SharedMemory> retain_buffer(request_info->buffer);
    407 
    408     base::TimeTicks time_start = base::TimeTicks::Now();
    409 
    410     const char* data_ptr = static_cast<char*>(request_info->buffer->memory());
    411     CHECK(data_ptr);
    412     CHECK(data_ptr + data_offset);
    413 
    414     request_info->peer->OnReceivedData(
    415         data_ptr + data_offset,
    416         data_length,
    417         encoded_data_length);
    418 
    419     UMA_HISTOGRAM_TIMES("ResourceDispatcher.OnReceivedDataTime",
    420                         base::TimeTicks::Now() - time_start);
    421   }
    422 
    423   // Acknowledge the reception of this data.
    424   message_sender()->Send(
    425       new ResourceHostMsg_DataReceived_ACK(message.routing_id(), request_id));
    426 }
    427 
    428 void ResourceDispatcher::OnDownloadedData(const IPC::Message& message,
    429                                           int request_id,
    430                                           int data_len) {
    431   // Acknowledge the reception of this message.
    432   message_sender()->Send(
    433       new ResourceHostMsg_DataDownloaded_ACK(message.routing_id(), request_id));
    434 
    435   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    436   if (!request_info)
    437     return;
    438 
    439   request_info->peer->OnDownloadedData(data_len);
    440 }
    441 
    442 void ResourceDispatcher::OnReceivedRedirect(
    443     const IPC::Message& message,
    444     int request_id,
    445     const GURL& new_url,
    446     const ResourceResponseHead& response_head) {
    447   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    448   if (!request_info)
    449     return;
    450   request_info->response_start = ConsumeIOTimestamp();
    451 
    452   int32 routing_id = message.routing_id();
    453   bool has_new_first_party_for_cookies = false;
    454   GURL new_first_party_for_cookies;
    455   ResourceResponseInfo renderer_response_info;
    456   ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
    457   if (request_info->peer->OnReceivedRedirect(new_url, renderer_response_info,
    458                                              &has_new_first_party_for_cookies,
    459                                              &new_first_party_for_cookies)) {
    460     // Double-check if the request is still around. The call above could
    461     // potentially remove it.
    462     request_info = GetPendingRequestInfo(request_id);
    463     if (!request_info)
    464       return;
    465     request_info->pending_redirect_message.reset(
    466         new ResourceHostMsg_FollowRedirect(routing_id, request_id,
    467                                            has_new_first_party_for_cookies,
    468                                            new_first_party_for_cookies));
    469     if (!request_info->is_deferred) {
    470       FollowPendingRedirect(request_id, *request_info);
    471     }
    472   } else {
    473     CancelPendingRequest(routing_id, request_id);
    474   }
    475 }
    476 
    477 void ResourceDispatcher::FollowPendingRedirect(
    478     int request_id,
    479     PendingRequestInfo& request_info) {
    480   IPC::Message* msg = request_info.pending_redirect_message.release();
    481   if (msg)
    482     message_sender()->Send(msg);
    483 }
    484 
    485 void ResourceDispatcher::OnRequestComplete(
    486     int request_id,
    487     int error_code,
    488     bool was_ignored_by_handler,
    489     const std::string& security_info,
    490     const base::TimeTicks& browser_completion_time) {
    491   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
    492   if (!request_info)
    493     return;
    494   request_info->completion_time = ConsumeIOTimestamp();
    495   request_info->buffer.reset();
    496   request_info->buffer_size = 0;
    497 
    498   ResourceLoaderBridge::Peer* peer = request_info->peer;
    499 
    500   if (delegate_) {
    501     ResourceLoaderBridge::Peer* new_peer =
    502         delegate_->OnRequestComplete(
    503             request_info->peer, request_info->resource_type, error_code);
    504     if (new_peer)
    505       request_info->peer = new_peer;
    506   }
    507 
    508   base::TimeTicks renderer_completion_time = ToRendererCompletionTime(
    509       *request_info, browser_completion_time);
    510   // The request ID will be removed from our pending list in the destructor.
    511   // Normally, dispatching this message causes the reference-counted request to
    512   // die immediately.
    513   peer->OnCompletedRequest(error_code, was_ignored_by_handler, security_info,
    514                            renderer_completion_time);
    515 }
    516 
    517 int ResourceDispatcher::AddPendingRequest(
    518     ResourceLoaderBridge::Peer* callback,
    519     ResourceType::Type resource_type,
    520     const GURL& request_url) {
    521   // Compute a unique request_id for this renderer process.
    522   int id = MakeRequestID();
    523   pending_requests_[id] =
    524       PendingRequestInfo(callback, resource_type, request_url);
    525   return id;
    526 }
    527 
    528 bool ResourceDispatcher::RemovePendingRequest(int request_id) {
    529   PendingRequestList::iterator it = pending_requests_.find(request_id);
    530   if (it == pending_requests_.end())
    531     return false;
    532 
    533   PendingRequestInfo& request_info = it->second;
    534   ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue);
    535   pending_requests_.erase(it);
    536 
    537   return true;
    538 }
    539 
    540 void ResourceDispatcher::CancelPendingRequest(int routing_id,
    541                                               int request_id) {
    542   PendingRequestList::iterator it = pending_requests_.find(request_id);
    543   if (it == pending_requests_.end()) {
    544     DVLOG(1) << "unknown request";
    545     return;
    546   }
    547 
    548   PendingRequestInfo& request_info = it->second;
    549   ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue);
    550   pending_requests_.erase(it);
    551 
    552   message_sender()->Send(
    553       new ResourceHostMsg_CancelRequest(routing_id, request_id));
    554 }
    555 
    556 void ResourceDispatcher::SetDefersLoading(int request_id, bool value) {
    557   PendingRequestList::iterator it = pending_requests_.find(request_id);
    558   if (it == pending_requests_.end()) {
    559     DLOG(ERROR) << "unknown request";
    560     return;
    561   }
    562   PendingRequestInfo& request_info = it->second;
    563   if (value) {
    564     request_info.is_deferred = value;
    565   } else if (request_info.is_deferred) {
    566     request_info.is_deferred = false;
    567 
    568     FollowPendingRedirect(request_id, request_info);
    569 
    570     base::MessageLoop::current()->PostTask(
    571         FROM_HERE,
    572         base::Bind(&ResourceDispatcher::FlushDeferredMessages,
    573                    weak_factory_.GetWeakPtr(),
    574                    request_id));
    575   }
    576 }
    577 
    578 void ResourceDispatcher::DidChangePriority(
    579     int routing_id, int request_id, net::RequestPriority new_priority) {
    580   DCHECK(ContainsKey(pending_requests_, request_id));
    581   message_sender()->Send(new ResourceHostMsg_DidChangePriority(
    582       routing_id, request_id, new_priority));
    583 }
    584 
    585 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo()
    586     : peer(NULL),
    587       resource_type(ResourceType::SUB_RESOURCE),
    588       is_deferred(false),
    589       buffer_size(0) {
    590 }
    591 
    592 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
    593     webkit_glue::ResourceLoaderBridge::Peer* peer,
    594     ResourceType::Type resource_type,
    595     const GURL& request_url)
    596     : peer(peer),
    597       resource_type(resource_type),
    598       is_deferred(false),
    599       url(request_url),
    600       request_start(base::TimeTicks::Now()) {
    601 }
    602 
    603 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {}
    604 
    605 void ResourceDispatcher::DispatchMessage(const IPC::Message& message) {
    606   IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message)
    607     IPC_MESSAGE_HANDLER(ResourceMsg_UploadProgress, OnUploadProgress)
    608     IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedResponse, OnReceivedResponse)
    609     IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedCachedMetadata,
    610                         OnReceivedCachedMetadata)
    611     IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect, OnReceivedRedirect)
    612     IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
    613     IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived, OnReceivedData)
    614     IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded, OnDownloadedData)
    615     IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete, OnRequestComplete)
    616   IPC_END_MESSAGE_MAP()
    617 }
    618 
    619 void ResourceDispatcher::FlushDeferredMessages(int request_id) {
    620   PendingRequestList::iterator it = pending_requests_.find(request_id);
    621   if (it == pending_requests_.end())  // The request could have become invalid.
    622     return;
    623   PendingRequestInfo& request_info = it->second;
    624   if (request_info.is_deferred)
    625     return;
    626   // Because message handlers could result in request_info being destroyed,
    627   // we need to work with a stack reference to the deferred queue.
    628   MessageQueue q;
    629   q.swap(request_info.deferred_message_queue);
    630   while (!q.empty()) {
    631     IPC::Message* m = q.front();
    632     q.pop_front();
    633     DispatchMessage(*m);
    634     delete m;
    635     // If this request is deferred in the context of the above message, then
    636     // we should honor the same and stop dispatching further messages.
    637     // We need to find the request again in the list as it may have completed
    638     // by now and the request_info instance above may be invalid.
    639     PendingRequestList::iterator index = pending_requests_.find(request_id);
    640     if (index != pending_requests_.end()) {
    641       PendingRequestInfo& pending_request = index->second;
    642       if (pending_request.is_deferred) {
    643         pending_request.deferred_message_queue.swap(q);
    644         return;
    645       }
    646     }
    647   }
    648 }
    649 
    650 ResourceLoaderBridge* ResourceDispatcher::CreateBridge(
    651     const ResourceLoaderBridge::RequestInfo& request_info) {
    652   return new IPCResourceLoaderBridge(this, request_info);
    653 }
    654 
    655 void ResourceDispatcher::ToResourceResponseInfo(
    656     const PendingRequestInfo& request_info,
    657     const ResourceResponseHead& browser_info,
    658     ResourceResponseInfo* renderer_info) const {
    659   *renderer_info = browser_info;
    660   if (request_info.request_start.is_null() ||
    661       request_info.response_start.is_null() ||
    662       browser_info.request_start.is_null() ||
    663       browser_info.response_start.is_null() ||
    664       browser_info.load_timing.request_start.is_null()) {
    665     return;
    666   }
    667   InterProcessTimeTicksConverter converter(
    668       LocalTimeTicks::FromTimeTicks(request_info.request_start),
    669       LocalTimeTicks::FromTimeTicks(request_info.response_start),
    670       RemoteTimeTicks::FromTimeTicks(browser_info.request_start),
    671       RemoteTimeTicks::FromTimeTicks(browser_info.response_start));
    672 
    673   net::LoadTimingInfo* load_timing = &renderer_info->load_timing;
    674   RemoteToLocalTimeTicks(converter, &load_timing->request_start);
    675   RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_start);
    676   RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_end);
    677   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_start);
    678   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_end);
    679   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_start);
    680   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_end);
    681   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_start);
    682   RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_end);
    683   RemoteToLocalTimeTicks(converter, &load_timing->send_start);
    684   RemoteToLocalTimeTicks(converter, &load_timing->send_end);
    685   RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end);
    686 }
    687 
    688 base::TimeTicks ResourceDispatcher::ToRendererCompletionTime(
    689     const PendingRequestInfo& request_info,
    690     const base::TimeTicks& browser_completion_time) const {
    691   if (request_info.completion_time.is_null()) {
    692     return browser_completion_time;
    693   }
    694 
    695   // TODO(simonjam): The optimal lower bound should be the most recent value of
    696   // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that?
    697   // Until then, |response_start| is used as it is the most recent value
    698   // returned for this request.
    699   int64 result = std::max(browser_completion_time.ToInternalValue(),
    700                           request_info.response_start.ToInternalValue());
    701   result = std::min(result, request_info.completion_time.ToInternalValue());
    702   return base::TimeTicks::FromInternalValue(result);
    703 }
    704 
    705 base::TimeTicks ResourceDispatcher::ConsumeIOTimestamp() {
    706   if (io_timestamp_ == base::TimeTicks())
    707     return base::TimeTicks::Now();
    708   base::TimeTicks result = io_timestamp_;
    709   io_timestamp_ = base::TimeTicks();
    710   return result;
    711 }
    712 
    713 // static
    714 bool ResourceDispatcher::IsResourceDispatcherMessage(
    715     const IPC::Message& message) {
    716   switch (message.type()) {
    717     case ResourceMsg_UploadProgress::ID:
    718     case ResourceMsg_ReceivedResponse::ID:
    719     case ResourceMsg_ReceivedCachedMetadata::ID:
    720     case ResourceMsg_ReceivedRedirect::ID:
    721     case ResourceMsg_SetDataBuffer::ID:
    722     case ResourceMsg_DataReceived::ID:
    723     case ResourceMsg_DataDownloaded::ID:
    724     case ResourceMsg_RequestComplete::ID:
    725       return true;
    726 
    727     default:
    728       break;
    729   }
    730 
    731   return false;
    732 }
    733 
    734 // static
    735 void ResourceDispatcher::ReleaseResourcesInDataMessage(
    736     const IPC::Message& message) {
    737   PickleIterator iter(message);
    738   int request_id;
    739   if (!message.ReadInt(&iter, &request_id)) {
    740     NOTREACHED() << "malformed resource message";
    741     return;
    742   }
    743 
    744   // If the message contains a shared memory handle, we should close the handle
    745   // or there will be a memory leak.
    746   if (message.type() == ResourceMsg_SetDataBuffer::ID) {
    747     base::SharedMemoryHandle shm_handle;
    748     if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message,
    749                                                          &iter,
    750                                                          &shm_handle)) {
    751       if (base::SharedMemory::IsHandleValid(shm_handle))
    752         base::SharedMemory::CloseHandle(shm_handle);
    753     }
    754   }
    755 }
    756 
    757 // static
    758 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
    759   while (!queue->empty()) {
    760     IPC::Message* message = queue->front();
    761     ReleaseResourcesInDataMessage(*message);
    762     queue->pop_front();
    763     delete message;
    764   }
    765 }
    766 
    767 }  // namespace content
    768