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