#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;
*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);
}
// 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.
return next_request_id++;
}
+} // namespace
+
// ResourceLoaderBridge implementation ----------------------------------------
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.
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() {
// 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_));
- }
}
}
}
// 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;
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_));
}
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) {
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;
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)
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);
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;
}
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;
}
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));
}
}
-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() {}