Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / child / resource_dispatcher.cc
index 990bf84..9e6e923 100644 (file)
 #include "content/child/request_extra_data.h"
 #include "content/child/request_info.h"
 #include "content/child/site_isolation_policy.h"
+#include "content/child/sync_load_response.h"
 #include "content/common/inter_process_time_ticks_converter.h"
 #include "content/common/resource_messages.h"
-#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/child/request_peer.h"
 #include "content/public/child/resource_dispatcher_delegate.h"
 #include "content/public/common/resource_response.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_response_headers.h"
+#include "webkit/child/resource_loader_bridge.h"
 #include "webkit/common/resource_type.h"
 
 using webkit_glue::ResourceLoaderBridge;
@@ -45,10 +47,7 @@ void RemoteToLocalTimeTicks(
   *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
 }
 
-
-}  // namespace
-
-static void CrashOnMapFailure() {
+void CrashOnMapFailure() {
 #if defined(OS_WIN)
   DWORD last_err = GetLastError();
   base::debug::Alias(&last_err);
@@ -57,7 +56,7 @@ static void CrashOnMapFailure() {
 }
 
 // Each resource request is assigned an ID scoped to this process.
-static int MakeRequestID() {
+int MakeRequestID() {
   // NOTE: The resource_dispatcher_host also needs probably unique
   // request_ids, so they count down from -2 (-1 is a special we're
   // screwed value), while the renderer process counts up.
@@ -65,6 +64,8 @@ static int MakeRequestID() {
   return next_request_id++;
 }
 
+}  // namespace
+
 // ResourceLoaderBridge implementation ----------------------------------------
 
 class IPCResourceLoaderBridge : public ResourceLoaderBridge {
@@ -75,14 +76,15 @@ class IPCResourceLoaderBridge : public ResourceLoaderBridge {
 
   // ResourceLoaderBridge
   virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE;
-  virtual bool Start(Peer* peer) OVERRIDE;
+  virtual bool Start(RequestPeer* peer) OVERRIDE;
   virtual void Cancel() OVERRIDE;
   virtual void SetDefersLoading(bool value) OVERRIDE;
-  virtual void DidChangePriority(net::RequestPriority new_priority) OVERRIDE;
+  virtual void DidChangePriority(net::RequestPriority new_priority,
+                                 int intra_priority_value) OVERRIDE;
   virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE;
 
  private:
-  ResourceLoaderBridge::Peer* peer_;
+  RequestPeer* peer_;
 
   // The resource dispatcher for this loader.  The bridge doesn't own it, but
   // it's guaranteed to outlive the bridge.
@@ -127,38 +129,29 @@ IPCResourceLoaderBridge::IPCResourceLoaderBridge(
   request_.appcache_host_id = request_info.appcache_host_id;
   request_.download_to_file = request_info.download_to_file;
   request_.has_user_gesture = request_info.has_user_gesture;
-  if (request_info.extra_data) {
-    RequestExtraData* extra_data =
-        static_cast<RequestExtraData*>(request_info.extra_data);
-    request_.visiblity_state = extra_data->visibility_state();
-    request_.render_frame_id = extra_data->render_frame_id();
-    request_.is_main_frame = extra_data->is_main_frame();
-    request_.parent_is_main_frame = extra_data->parent_is_main_frame();
-    request_.parent_render_frame_id = extra_data->parent_render_frame_id();
-    request_.allow_download = extra_data->allow_download();
-    request_.transition_type = extra_data->transition_type();
-    request_.should_replace_current_entry =
-        extra_data->should_replace_current_entry();
-    request_.transferred_request_child_id =
-        extra_data->transferred_request_child_id();
-    request_.transferred_request_request_id =
-        extra_data->transferred_request_request_id();
-    request_.service_worker_provider_id =
-        extra_data->service_worker_provider_id();
-    frame_origin_ = extra_data->frame_origin();
-  } else {
-    request_.visiblity_state = blink::WebPageVisibilityStateVisible;
-    request_.render_frame_id = MSG_ROUTING_NONE;
-    request_.is_main_frame = false;
-    request_.parent_is_main_frame = false;
-    request_.parent_render_frame_id = -1;
-    request_.allow_download = true;
-    request_.transition_type = PAGE_TRANSITION_LINK;
-    request_.should_replace_current_entry = false;
-    request_.transferred_request_child_id = -1;
-    request_.transferred_request_request_id = -1;
-    request_.service_worker_provider_id = kInvalidServiceWorkerProviderId;
-  }
+
+  const RequestExtraData kEmptyData;
+  const RequestExtraData* extra_data;
+  if (request_info.extra_data)
+    extra_data = static_cast<RequestExtraData*>(request_info.extra_data);
+  else
+    extra_data = &kEmptyData;
+  request_.visiblity_state = extra_data->visibility_state();
+  request_.render_frame_id = extra_data->render_frame_id();
+  request_.is_main_frame = extra_data->is_main_frame();
+  request_.parent_is_main_frame = extra_data->parent_is_main_frame();
+  request_.parent_render_frame_id = extra_data->parent_render_frame_id();
+  request_.allow_download = extra_data->allow_download();
+  request_.transition_type = extra_data->transition_type();
+  request_.should_replace_current_entry =
+      extra_data->should_replace_current_entry();
+  request_.transferred_request_child_id =
+      extra_data->transferred_request_child_id();
+  request_.transferred_request_request_id =
+      extra_data->transferred_request_request_id();
+  request_.service_worker_provider_id =
+      extra_data->service_worker_provider_id();
+  frame_origin_ = extra_data->frame_origin();
 }
 
 IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
@@ -168,11 +161,6 @@ IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
     // this operation may fail, as the dispatcher will have preemptively
     // removed us when the renderer sends the ReceivedAllData message.
     dispatcher_->RemovePendingRequest(request_id_);
-
-    if (request_.download_to_file) {
-      dispatcher_->message_sender()->Send(
-          new ResourceHostMsg_ReleaseDownloadedFile(request_id_));
-    }
   }
 }
 
@@ -183,7 +171,7 @@ void IPCResourceLoaderBridge::SetRequestBody(
 }
 
 // Writes a footer on the message and sends it
-bool IPCResourceLoaderBridge::Start(Peer* peer) {
+bool IPCResourceLoaderBridge::Start(RequestPeer* peer) {
   if (request_id_ != -1) {
     NOTREACHED() << "Starting a request twice";
     return false;
@@ -196,7 +184,8 @@ bool IPCResourceLoaderBridge::Start(Peer* peer) {
                                                request_.resource_type,
                                                request_.origin_pid,
                                                frame_origin_,
-                                               request_.url);
+                                               request_.url,
+                                               request_.download_to_file);
 
   return dispatcher_->message_sender()->Send(
       new ResourceHostMsg_RequestResource(routing_id_, request_id_, request_));
@@ -226,13 +215,14 @@ void IPCResourceLoaderBridge::SetDefersLoading(bool value) {
 }
 
 void IPCResourceLoaderBridge::DidChangePriority(
-    net::RequestPriority new_priority) {
+    net::RequestPriority new_priority, int intra_priority_value) {
   if (request_id_ < 0) {
     NOTREACHED() << "Trying to change priority of an unstarted request";
     return;
   }
 
-  dispatcher_->DidChangePriority(routing_id_, request_id_, new_priority);
+  dispatcher_->DidChangePriority(routing_id_, request_id_, new_priority,
+                                 intra_priority_value);
 }
 
 void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
@@ -302,6 +292,18 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
     return true;
   }
 
+  // If the request has been canceled, only dispatch
+  // ResourceMsg_RequestComplete (otherwise resource leaks) and drop other
+  // messages.
+  if (request_info->is_canceled) {
+    if (message.type() == ResourceMsg_RequestComplete::ID) {
+      DispatchMessage(message);
+    } else {
+      ReleaseResourcesInDataMessage(message);
+    }
+    return true;
+  }
+
   if (request_info->is_deferred) {
     request_info->deferred_message_queue.push_back(new IPC::Message(message));
     return true;
@@ -354,7 +356,7 @@ void ResourceDispatcher::OnReceivedResponse(
   request_info->response_start = ConsumeIOTimestamp();
 
   if (delegate_) {
-    ResourceLoaderBridge::Peer* new_peer =
+    RequestPeer* new_peer =
         delegate_->OnReceivedResponse(
             request_info->peer, response_head.mime_type, request_info->url);
     if (new_peer)
@@ -538,10 +540,10 @@ void ResourceDispatcher::OnRequestComplete(
   request_info->buffer.reset();
   request_info->buffer_size = 0;
 
-  ResourceLoaderBridge::Peer* peer = request_info->peer;
+  RequestPeer* peer = request_info->peer;
 
   if (delegate_) {
-    ResourceLoaderBridge::Peer* new_peer =
+    RequestPeer* new_peer =
         delegate_->OnRequestComplete(
             request_info->peer, request_info->resource_type,
             request_complete_data.error_code);
@@ -562,16 +564,20 @@ void ResourceDispatcher::OnRequestComplete(
                            request_complete_data.encoded_data_length);
 }
 
-int ResourceDispatcher::AddPendingRequest(
-    ResourceLoaderBridge::Peer* callback,
-    ResourceType::Type resource_type,
-    int origin_pid,
-    const GURL& frame_origin,
-    const GURL& request_url) {
+int ResourceDispatcher::AddPendingRequest(RequestPeer* callback,
+                                          ResourceType::Type resource_type,
+                                          int origin_pid,
+                                          const GURL& frame_origin,
+                                          const GURL& request_url,
+                                          bool download_to_file) {
   // Compute a unique request_id for this renderer process.
   int id = MakeRequestID();
-  pending_requests_[id] = PendingRequestInfo(
-      callback, resource_type, origin_pid, frame_origin, request_url);
+  pending_requests_[id] = PendingRequestInfo(callback,
+                                             resource_type,
+                                             origin_pid,
+                                             frame_origin,
+                                             request_url,
+                                             download_to_file);
   return id;
 }
 
@@ -581,9 +587,17 @@ bool ResourceDispatcher::RemovePendingRequest(int request_id) {
     return false;
 
   PendingRequestInfo& request_info = it->second;
+
+  bool release_downloaded_file = request_info.download_to_file;
+
   ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue);
   pending_requests_.erase(it);
 
+  if (release_downloaded_file) {
+    message_sender_->Send(
+        new ResourceHostMsg_ReleaseDownloadedFile(request_id));
+  }
+
   return true;
 }
 
@@ -594,6 +608,46 @@ void ResourceDispatcher::CancelPendingRequest(int request_id) {
     return;
   }
 
+  PendingRequestInfo& request_info = it->second;
+  request_info.is_canceled = true;
+
+  // Because message handlers could result in request_info being destroyed,
+  // we need to work with a stack reference to the deferred queue.
+  MessageQueue queue;
+  queue.swap(request_info.deferred_message_queue);
+  // Removes pending requests. If ResourceMsg_RequestComplete was queued,
+  // dispatch it.
+  bool first_message = true;
+  while (!queue.empty()) {
+    IPC::Message* message = queue.front();
+    if (message->type() == ResourceMsg_RequestComplete::ID) {
+      if (first_message) {
+        // Dispatch as-is.
+        DispatchMessage(*message);
+      } else {
+        // If we skip some ResourceMsg_DataReceived and then dispatched the
+        // original ResourceMsg_RequestComplete(status=success), chrome will
+        // crash because it entered an unexpected state. So replace
+        // ResourceMsg_RequestComplete with failure status.
+        ResourceMsg_RequestCompleteData request_complete_data;
+        request_complete_data.error_code = net::ERR_ABORTED;
+        request_complete_data.was_ignored_by_handler = false;
+        request_complete_data.exists_in_cache = false;
+        request_complete_data.completion_time = base::TimeTicks();
+        request_complete_data.encoded_data_length = 0;
+
+        ResourceMsg_RequestComplete error_message(request_id,
+            request_complete_data);
+        DispatchMessage(error_message);
+      }
+    } else {
+      ReleaseResourcesInDataMessage(*message);
+    }
+    first_message = false;
+    queue.pop_front();
+    delete message;
+  }
+
   // |request_id| will be removed from |pending_requests_| when
   // OnRequestComplete returns with ERR_ABORTED.
   message_sender()->Send(new ResourceHostMsg_CancelRequest(request_id));
@@ -621,37 +675,43 @@ void ResourceDispatcher::SetDefersLoading(int request_id, bool value) {
   }
 }
 
-void ResourceDispatcher::DidChangePriority(
-    int routing_id, int request_id, net::RequestPriority new_priority) {
+void ResourceDispatcher::DidChangePriority(int routing_id,
+                                           int request_id,
+                                           net::RequestPriority new_priority,
+                                           int intra_priority_value) {
   DCHECK(ContainsKey(pending_requests_, request_id));
   message_sender()->Send(new ResourceHostMsg_DidChangePriority(
-      request_id, new_priority));
+      request_id, new_priority, intra_priority_value));
 }
 
 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo()
     : peer(NULL),
       resource_type(ResourceType::SUB_RESOURCE),
       is_deferred(false),
+      is_canceled(false),
+      download_to_file(false),
       blocked_response(false),
       buffer_size(0) {
 }
 
 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
-    webkit_glue::ResourceLoaderBridge::Peer* peer,
+    RequestPeer* peer,
     ResourceType::Type resource_type,
     int origin_pid,
     const GURL& frame_origin,
-    const GURL& request_url)
+    const GURL& request_url,
+    bool download_to_file)
     : peer(peer),
       resource_type(resource_type),
       origin_pid(origin_pid),
       is_deferred(false),
+      is_canceled(false),
       url(request_url),
       frame_origin(frame_origin),
       response_url(request_url),
+      download_to_file(download_to_file),
       request_start(base::TimeTicks::Now()),
-      blocked_response(false) {
-}
+      blocked_response(false) {}
 
 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {}